aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/lldb/API/LLDB.h1
-rw-r--r--include/lldb/API/SBAddress.h2
-rw-r--r--include/lldb/API/SBAttachInfo.h149
-rw-r--r--include/lldb/API/SBBlock.h2
-rw-r--r--include/lldb/API/SBBreakpoint.h2
-rw-r--r--include/lldb/API/SBBreakpointLocation.h6
-rw-r--r--include/lldb/API/SBBroadcaster.h2
-rw-r--r--include/lldb/API/SBCommandInterpreter.h33
-rw-r--r--include/lldb/API/SBCommandReturnObject.h2
-rw-r--r--include/lldb/API/SBCommunication.h5
-rw-r--r--include/lldb/API/SBCompileUnit.h2
-rw-r--r--include/lldb/API/SBData.h2
-rw-r--r--include/lldb/API/SBDebugger.h4
-rw-r--r--include/lldb/API/SBDeclaration.h2
-rw-r--r--include/lldb/API/SBDefines.h3
-rw-r--r--include/lldb/API/SBError.h2
-rw-r--r--include/lldb/API/SBEvent.h3
-rw-r--r--include/lldb/API/SBExecutionContext.h2
-rw-r--r--include/lldb/API/SBExpressionOptions.h8
-rw-r--r--include/lldb/API/SBFileSpec.h2
-rw-r--r--include/lldb/API/SBFileSpecList.h2
-rw-r--r--include/lldb/API/SBFrame.h21
-rw-r--r--include/lldb/API/SBFunction.h2
-rw-r--r--include/lldb/API/SBHostOS.h2
-rw-r--r--include/lldb/API/SBInstruction.h2
-rw-r--r--include/lldb/API/SBInstructionList.h2
-rw-r--r--include/lldb/API/SBLanguageRuntime.h29
-rw-r--r--include/lldb/API/SBLaunchInfo.h13
-rw-r--r--include/lldb/API/SBLineEntry.h2
-rw-r--r--include/lldb/API/SBListener.h2
-rw-r--r--include/lldb/API/SBModule.h21
-rw-r--r--include/lldb/API/SBModuleSpec.h2
-rw-r--r--include/lldb/API/SBPlatform.h6
-rw-r--r--include/lldb/API/SBProcess.h24
-rw-r--r--include/lldb/API/SBQueue.h2
-rw-r--r--include/lldb/API/SBQueueItem.h2
-rw-r--r--include/lldb/API/SBSection.h2
-rw-r--r--include/lldb/API/SBSourceManager.h2
-rw-r--r--include/lldb/API/SBStream.h2
-rw-r--r--include/lldb/API/SBStringList.h2
-rw-r--r--include/lldb/API/SBSymbol.h2
-rw-r--r--include/lldb/API/SBSymbolContext.h2
-rw-r--r--include/lldb/API/SBSymbolContextList.h2
-rw-r--r--include/lldb/API/SBTarget.h165
-rw-r--r--include/lldb/API/SBThread.h2
-rw-r--r--include/lldb/API/SBThreadCollection.h2
-rw-r--r--include/lldb/API/SBThreadPlan.h2
-rw-r--r--include/lldb/API/SBType.h2
-rw-r--r--include/lldb/API/SBTypeCategory.h2
-rw-r--r--include/lldb/API/SBTypeEnumMember.h2
-rw-r--r--include/lldb/API/SBTypeFilter.h2
-rw-r--r--include/lldb/API/SBTypeFormat.h2
-rw-r--r--include/lldb/API/SBTypeNameSpecifier.h2
-rw-r--r--include/lldb/API/SBTypeSummary.h2
-rw-r--r--include/lldb/API/SBTypeSynthetic.h2
-rw-r--r--include/lldb/API/SBUnixSignals.h2
-rw-r--r--include/lldb/API/SBValue.h14
-rw-r--r--include/lldb/API/SBValueList.h2
-rw-r--r--include/lldb/API/SBVariablesOptions.h98
-rw-r--r--include/lldb/API/SBWatchpoint.h2
-rw-r--r--include/lldb/API/SystemInitializerFull.h40
-rw-r--r--include/lldb/Breakpoint/Breakpoint.h58
-rw-r--r--include/lldb/Breakpoint/BreakpointLocation.h5
-rw-r--r--include/lldb/Breakpoint/BreakpointOptions.h3
-rw-r--r--include/lldb/Breakpoint/BreakpointResolverFileLine.h4
-rw-r--r--include/lldb/Breakpoint/BreakpointResolverFileRegex.h4
-rw-r--r--include/lldb/Breakpoint/BreakpointSite.h2
-rw-r--r--include/lldb/Breakpoint/Watchpoint.h18
-rw-r--r--include/lldb/Core/Address.h2
-rw-r--r--include/lldb/Core/ArchSpec.h141
-rw-r--r--include/lldb/Core/ClangForward.h3
-rw-r--r--include/lldb/Core/Communication.h30
-rw-r--r--include/lldb/Core/Connection.h23
-rw-r--r--include/lldb/Core/ConstString.h2
-rw-r--r--include/lldb/Core/CxaDemangle.h21
-rw-r--r--include/lldb/Core/DataEncoder.h4
-rw-r--r--include/lldb/Core/DataExtractor.h14
-rw-r--r--include/lldb/Core/Debugger.h30
-rw-r--r--include/lldb/Core/Disassembler.h11
-rw-r--r--include/lldb/Core/FastDemangle.h24
-rw-r--r--include/lldb/Core/FormatEntity.h3
-rw-r--r--include/lldb/Core/IOHandler.h150
-rw-r--r--include/lldb/Core/Log.h140
-rw-r--r--include/lldb/Core/Logging.h (renamed from include/lldb/lldb-private-log.h)9
-rw-r--r--include/lldb/Core/Mangled.h17
-rw-r--r--include/lldb/Core/Module.h12
-rw-r--r--include/lldb/Core/ModuleList.h4
-rw-r--r--include/lldb/Core/ModuleSpec.h33
-rw-r--r--include/lldb/Core/PluginManager.h6
-rw-r--r--include/lldb/Core/RangeMap.h27
-rw-r--r--include/lldb/Core/StreamAsynchronousIO.h8
-rw-r--r--include/lldb/Core/StreamFile.h4
-rw-r--r--include/lldb/Core/StringList.h4
-rw-r--r--include/lldb/Core/StructuredData.h406
-rw-r--r--include/lldb/Core/ThreadSafeDenseSet.h65
-rw-r--r--include/lldb/Core/ValueObject.h65
-rw-r--r--include/lldb/Core/ValueObjectChild.h3
-rw-r--r--include/lldb/Core/ValueObjectDynamicValue.h12
-rw-r--r--include/lldb/Core/ValueObjectSyntheticFilter.h15
-rw-r--r--include/lldb/DataFormatters/CXXFormatterFunctions.h35
-rw-r--r--include/lldb/DataFormatters/FormatManager.h4
-rw-r--r--include/lldb/DataFormatters/TypeFormat.h27
-rw-r--r--include/lldb/DataFormatters/TypeSummary.h33
-rw-r--r--include/lldb/DataFormatters/TypeSynthetic.h30
-rw-r--r--include/lldb/DataFormatters/TypeValidator.h27
-rw-r--r--include/lldb/DataFormatters/ValueObjectPrinter.h5
-rw-r--r--include/lldb/DataFormatters/VectorType.h (renamed from tools/lldb-platform/exports)0
-rw-r--r--include/lldb/Expression/ClangASTSource.h127
-rw-r--r--include/lldb/Expression/ClangExpressionDeclMap.h21
-rw-r--r--include/lldb/Expression/ClangExpressionParser.h1
-rw-r--r--include/lldb/Expression/ClangFunction.h3
-rw-r--r--include/lldb/Expression/ClangModulesDeclVendor.h73
-rw-r--r--include/lldb/Expression/ClangPersistentVariables.h16
-rw-r--r--include/lldb/Expression/ClangUserExpression.h13
-rw-r--r--include/lldb/Expression/IRForTarget.h3
-rw-r--r--include/lldb/Expression/IRMemoryMap.h12
-rw-r--r--include/lldb/Expression/IRToDWARF.h2
-rw-r--r--include/lldb/Host/Editline.h18
-rw-r--r--include/lldb/Host/File.h2
-rw-r--r--include/lldb/Host/FileSpec.h131
-rw-r--r--include/lldb/Host/FileSystem.h31
-rw-r--r--include/lldb/Host/Host.h45
-rw-r--r--include/lldb/Host/HostInfo.h5
-rw-r--r--include/lldb/Host/HostInfoBase.h4
-rw-r--r--include/lldb/Host/LockFile.h27
-rw-r--r--include/lldb/Host/LockFileBase.h73
-rw-r--r--include/lldb/Host/PipeBase.h2
-rw-r--r--include/lldb/Host/Socket.h7
-rw-r--r--include/lldb/Host/Time.h26
-rw-r--r--include/lldb/Host/XML.h234
-rw-r--r--include/lldb/Host/common/NativeBreakpointList.h3
-rw-r--r--include/lldb/Host/common/NativeProcessProtocol.h20
-rw-r--r--include/lldb/Host/common/NativeRegisterContext.h19
-rw-r--r--include/lldb/Host/common/SoftwareBreakpoint.h2
-rw-r--r--include/lldb/Host/posix/ConnectionFileDescriptorPosix.h18
-rw-r--r--include/lldb/Host/posix/Fcntl.h25
-rw-r--r--include/lldb/Host/posix/HostProcessPosix.h10
-rw-r--r--include/lldb/Host/posix/HostThreadPosix.h4
-rw-r--r--include/lldb/Host/posix/LockFilePosix.h42
-rw-r--r--include/lldb/Host/posix/PipePosix.h17
-rw-r--r--include/lldb/Host/posix/ProcessLauncherPosix.h2
-rw-r--r--include/lldb/Initialization/SystemInitializer.h26
-rw-r--r--include/lldb/Initialization/SystemInitializerCommon.h38
-rw-r--r--include/lldb/Initialization/SystemLifetimeManager.h42
-rw-r--r--include/lldb/Interpreter/Args.h17
-rw-r--r--include/lldb/Interpreter/CommandInterpreter.h13
-rw-r--r--include/lldb/Interpreter/CommandObject.h90
-rw-r--r--include/lldb/Interpreter/OptionValue.h16
-rw-r--r--include/lldb/Interpreter/OptionValueArch.h2
-rw-r--r--include/lldb/Interpreter/OptionValueArray.h2
-rw-r--r--include/lldb/Interpreter/OptionValueBoolean.h2
-rw-r--r--include/lldb/Interpreter/OptionValueChar.h2
-rw-r--r--include/lldb/Interpreter/OptionValueDictionary.h2
-rw-r--r--include/lldb/Interpreter/OptionValueEnumeration.h2
-rw-r--r--include/lldb/Interpreter/OptionValueFileSpec.h13
-rw-r--r--include/lldb/Interpreter/OptionValueFileSpecList.h2
-rw-r--r--include/lldb/Interpreter/OptionValueFormat.h2
-rw-r--r--include/lldb/Interpreter/OptionValueFormatEntity.h2
-rw-r--r--include/lldb/Interpreter/OptionValueLanguage.h107
-rw-r--r--include/lldb/Interpreter/OptionValuePathMappings.h2
-rw-r--r--include/lldb/Interpreter/OptionValueProperties.h2
-rw-r--r--include/lldb/Interpreter/OptionValueRegex.h2
-rw-r--r--include/lldb/Interpreter/OptionValueSInt64.h2
-rw-r--r--include/lldb/Interpreter/OptionValueString.h2
-rw-r--r--include/lldb/Interpreter/OptionValueUInt64.h2
-rw-r--r--include/lldb/Interpreter/OptionValueUUID.h2
-rw-r--r--include/lldb/Interpreter/OptionValues.h1
-rw-r--r--include/lldb/Interpreter/PythonDataObjects.h107
-rw-r--r--include/lldb/Interpreter/ScriptInterpreter.h323
-rw-r--r--include/lldb/Interpreter/ScriptInterpreterPython.h288
-rw-r--r--include/lldb/Symbol/ClangASTContext.h2
-rw-r--r--include/lldb/Symbol/ClangASTType.h4
-rw-r--r--include/lldb/Symbol/ClangExternalASTSourceCallbacks.h76
-rw-r--r--include/lldb/Symbol/CompileUnit.h25
-rw-r--r--include/lldb/Symbol/DWARFCallFrameInfo.h10
-rw-r--r--include/lldb/Symbol/FuncUnwinders.h4
-rw-r--r--include/lldb/Symbol/ObjectFile.h7
-rw-r--r--include/lldb/Symbol/Symbol.h88
-rw-r--r--include/lldb/Symbol/SymbolContext.h29
-rw-r--r--include/lldb/Symbol/SymbolFile.h1
-rw-r--r--include/lldb/Symbol/SymbolVendor.h7
-rw-r--r--include/lldb/Symbol/Symtab.h8
-rw-r--r--include/lldb/Symbol/Type.h12
-rw-r--r--include/lldb/Symbol/UnwindPlan.h248
-rw-r--r--include/lldb/Symbol/Variable.h2
-rw-r--r--include/lldb/Target/CPPLanguageRuntime.h3
-rw-r--r--include/lldb/Target/FileAction.h17
-rw-r--r--include/lldb/Target/LanguageRuntime.h30
-rw-r--r--include/lldb/Target/Memory.h17
-rw-r--r--include/lldb/Target/ObjCLanguageRuntime.h62
-rw-r--r--include/lldb/Target/Platform.h150
-rw-r--r--include/lldb/Target/Process.h262
-rw-r--r--include/lldb/Target/ProcessInfo.h2
-rw-r--r--include/lldb/Target/ProcessLaunchInfo.h36
-rw-r--r--include/lldb/Target/SectionLoadHistory.h2
-rw-r--r--include/lldb/Target/StopInfo.h8
-rw-r--r--include/lldb/Target/Target.h223
-rw-r--r--include/lldb/Target/Thread.h50
-rw-r--r--include/lldb/Target/ThreadPlanCallUserExpression.h13
-rw-r--r--include/lldb/Target/ThreadPlanPython.h5
-rw-r--r--include/lldb/Utility/ConvertEnum.h22
-rw-r--r--include/lldb/Utility/JSON.h276
-rw-r--r--include/lldb/Utility/LLDBAssert.h30
-rw-r--r--include/lldb/Utility/NameMatches.h19
-rw-r--r--include/lldb/Utility/PseudoTerminal.h4
-rw-r--r--include/lldb/Utility/SharingPtr.h11
-rw-r--r--include/lldb/lldb-defines.h2
-rw-r--r--include/lldb/lldb-enumerations.h334
-rw-r--r--include/lldb/lldb-forward.h33
-rw-r--r--include/lldb/lldb-private-interfaces.h1
-rw-r--r--include/lldb/lldb-private-types.h11
-rw-r--r--include/lldb/lldb-private.h53
-rw-r--r--source/API/SBAddress.cpp2
-rw-r--r--source/API/SBAttachInfo.cpp242
-rw-r--r--source/API/SBCommandInterpreter.cpp242
-rw-r--r--source/API/SBDebugger.cpp63
-rw-r--r--source/API/SBEvent.cpp2
-rw-r--r--source/API/SBExpressionOptions.cpp11
-rw-r--r--source/API/SBFileSpec.cpp14
-rw-r--r--source/API/SBFrame.cpp115
-rw-r--r--source/API/SBInstruction.cpp4
-rw-r--r--source/API/SBInstructionList.cpp2
-rw-r--r--source/API/SBLanguageRuntime.cpp26
-rw-r--r--source/API/SBLaunchInfo.cpp26
-rw-r--r--source/API/SBListener.cpp2
-rw-r--r--source/API/SBModule.cpp64
-rw-r--r--source/API/SBPlatform.cpp14
-rw-r--r--source/API/SBProcess.cpp52
-rw-r--r--source/API/SBQueue.cpp2
-rw-r--r--source/API/SBQueueItem.cpp1
-rw-r--r--source/API/SBSourceManager.cpp2
-rw-r--r--source/API/SBSymbol.cpp9
-rw-r--r--source/API/SBTarget.cpp556
-rw-r--r--source/API/SBThread.cpp12
-rw-r--r--source/API/SBThreadPlan.cpp2
-rw-r--r--source/API/SBTypeCategory.cpp2
-rw-r--r--source/API/SBTypeFilter.cpp2
-rw-r--r--source/API/SBTypeFormat.cpp2
-rw-r--r--source/API/SBTypeNameSpecifier.cpp2
-rw-r--r--source/API/SBTypeSummary.cpp2
-rw-r--r--source/API/SBTypeSynthetic.cpp2
-rw-r--r--source/API/SBValue.cpp57
-rw-r--r--source/API/SBVariablesOptions.cpp254
-rw-r--r--source/API/SystemInitializerFull.cpp392
-rw-r--r--source/Breakpoint/Breakpoint.cpp46
-rw-r--r--source/Breakpoint/BreakpointLocation.cpp8
-rw-r--r--source/Breakpoint/BreakpointLocationCollection.cpp10
-rw-r--r--source/Breakpoint/BreakpointResolver.cpp1
-rw-r--r--source/Breakpoint/BreakpointResolverAddress.cpp2
-rw-r--r--source/Breakpoint/BreakpointResolverFileLine.cpp14
-rw-r--r--source/Breakpoint/BreakpointResolverFileRegex.cpp14
-rw-r--r--source/Breakpoint/BreakpointSite.cpp3
-rw-r--r--source/Commands/CommandCompletions.cpp3
-rw-r--r--source/Commands/CommandObjectApropos.cpp3
-rw-r--r--source/Commands/CommandObjectArgs.cpp4
-rw-r--r--source/Commands/CommandObjectBreakpoint.cpp108
-rw-r--r--source/Commands/CommandObjectBreakpointCommand.cpp2
-rw-r--r--source/Commands/CommandObjectBugreport.cpp145
-rw-r--r--source/Commands/CommandObjectBugreport.h36
-rw-r--r--source/Commands/CommandObjectCommands.cpp264
-rw-r--r--source/Commands/CommandObjectDisassemble.cpp2
-rw-r--r--source/Commands/CommandObjectExpression.cpp6
-rw-r--r--source/Commands/CommandObjectFrame.cpp50
-rw-r--r--source/Commands/CommandObjectGUI.cpp2
-rw-r--r--source/Commands/CommandObjectHelp.cpp2
-rw-r--r--source/Commands/CommandObjectLanguage.cpp44
-rw-r--r--source/Commands/CommandObjectLanguage.h41
-rw-r--r--source/Commands/CommandObjectLog.cpp6
-rw-r--r--source/Commands/CommandObjectMemory.cpp44
-rw-r--r--source/Commands/CommandObjectMultiword.cpp38
-rw-r--r--source/Commands/CommandObjectPlatform.cpp25
-rw-r--r--source/Commands/CommandObjectPlugin.cpp2
-rw-r--r--source/Commands/CommandObjectProcess.cpp155
-rw-r--r--source/Commands/CommandObjectQuit.cpp3
-rw-r--r--source/Commands/CommandObjectRegister.cpp21
-rw-r--r--source/Commands/CommandObjectSettings.cpp5
-rw-r--r--source/Commands/CommandObjectSource.cpp12
-rw-r--r--source/Commands/CommandObjectSyntax.cpp2
-rw-r--r--source/Commands/CommandObjectTarget.cpp193
-rw-r--r--source/Commands/CommandObjectThread.cpp110
-rw-r--r--source/Commands/CommandObjectType.cpp4
-rw-r--r--source/Commands/CommandObjectVersion.cpp2
-rw-r--r--source/Commands/CommandObjectWatchpoint.cpp21
-rw-r--r--source/Commands/CommandObjectWatchpointCommand.cpp2
-rw-r--r--source/Core/Address.cpp26
-rw-r--r--source/Core/AddressResolver.cpp1
-rw-r--r--source/Core/AddressResolverFileLine.cpp1
-rw-r--r--source/Core/AddressResolverName.cpp5
-rw-r--r--source/Core/ArchSpec.cpp150
-rw-r--r--source/Core/Broadcaster.cpp1
-rw-r--r--source/Core/Communication.cpp43
-rw-r--r--source/Core/ConnectionMachPort.cpp5
-rw-r--r--source/Core/ConnectionSharedMemory.cpp1
-rw-r--r--source/Core/CxaDemangle.cpp5011
-rw-r--r--source/Core/DataBufferHeap.cpp2
-rw-r--r--source/Core/DataBufferMemoryMap.cpp14
-rw-r--r--source/Core/DataEncoder.cpp14
-rw-r--r--source/Core/DataExtractor.cpp2
-rw-r--r--source/Core/Debugger.cpp301
-rw-r--r--source/Core/Disassembler.cpp110
-rw-r--r--source/Core/DynamicLoader.cpp18
-rw-r--r--source/Core/Error.cpp4
-rw-r--r--source/Core/FastDemangle.cpp13
-rw-r--r--source/Core/FileLineResolver.cpp1
-rw-r--r--source/Core/FormatEntity.cpp66
-rw-r--r--source/Core/IOHandler.cpp272
-rw-r--r--source/Core/Language.cpp20
-rw-r--r--source/Core/Listener.cpp1
-rw-r--r--source/Core/Log.cpp284
-rw-r--r--source/Core/Logging.cpp (renamed from source/lldb-log.cpp)8
-rw-r--r--source/Core/Mangled.cpp5061
-rw-r--r--source/Core/Module.cpp77
-rw-r--r--source/Core/ModuleList.cpp56
-rw-r--r--source/Core/PluginManager.cpp17
-rw-r--r--source/Core/Scalar.cpp6
-rw-r--r--source/Core/SearchFilter.cpp2
-rw-r--r--source/Core/Section.cpp1
-rw-r--r--source/Core/SourceManager.cpp3
-rw-r--r--source/Core/StreamAsynchronousIO.cpp25
-rw-r--r--source/Core/StreamFile.cpp7
-rw-r--r--source/Core/StringList.cpp6
-rw-r--r--source/Core/StructuredData.cpp67
-rw-r--r--source/Core/UUID.cpp3
-rw-r--r--source/Core/UserSettingsController.cpp3
-rw-r--r--source/Core/ValueObject.cpp242
-rw-r--r--source/Core/ValueObjectChild.cpp8
-rw-r--r--source/Core/ValueObjectConstResult.cpp2
-rw-r--r--source/Core/ValueObjectSyntheticFilter.cpp14
-rw-r--r--source/Core/ValueObjectVariable.cpp2
-rw-r--r--source/DataFormatters/CF.cpp2
-rw-r--r--source/DataFormatters/CXXFormatterFunctions.cpp7
-rw-r--r--source/DataFormatters/Cocoa.cpp2
-rw-r--r--source/DataFormatters/CoreMedia.cpp85
-rw-r--r--source/DataFormatters/DataVisualization.cpp2
-rw-r--r--source/DataFormatters/FormatCache.cpp2
-rw-r--r--source/DataFormatters/FormatManager.cpp73
-rw-r--r--source/DataFormatters/LibCxx.cpp4
-rw-r--r--source/DataFormatters/LibCxxInitializerList.cpp2
-rw-r--r--source/DataFormatters/LibCxxList.cpp2
-rw-r--r--source/DataFormatters/LibCxxMap.cpp2
-rw-r--r--source/DataFormatters/LibCxxUnorderedMap.cpp2
-rw-r--r--source/DataFormatters/LibCxxVector.cpp2
-rw-r--r--source/DataFormatters/LibStdcpp.cpp171
-rw-r--r--source/DataFormatters/NSArray.cpp2
-rw-r--r--source/DataFormatters/NSDictionary.cpp2
-rw-r--r--source/DataFormatters/NSIndexPath.cpp219
-rw-r--r--source/DataFormatters/NSSet.cpp2
-rw-r--r--source/DataFormatters/StringPrinter.cpp32
-rw-r--r--source/DataFormatters/TypeCategory.cpp2
-rw-r--r--source/DataFormatters/TypeCategoryMap.cpp2
-rw-r--r--source/DataFormatters/TypeFormat.cpp3
-rw-r--r--source/DataFormatters/TypeSummary.cpp2
-rw-r--r--source/DataFormatters/TypeSynthetic.cpp6
-rw-r--r--source/DataFormatters/ValueObjectPrinter.cpp28
-rw-r--r--source/DataFormatters/VectorType.cpp276
-rw-r--r--source/Expression/ClangASTSource.cpp142
-rw-r--r--source/Expression/ClangExpressionDeclMap.cpp292
-rw-r--r--source/Expression/ClangExpressionParser.cpp48
-rw-r--r--source/Expression/ClangModulesDeclVendor.cpp398
-rw-r--r--source/Expression/ClangUserExpression.cpp97
-rw-r--r--source/Expression/DWARFExpression.cpp26
-rw-r--r--source/Expression/ExpressionSourceCode.cpp98
-rw-r--r--source/Expression/IRExecutionUnit.cpp25
-rw-r--r--source/Expression/IRForTarget.cpp94
-rw-r--r--source/Expression/Materializer.cpp3
-rw-r--r--source/Host/common/Editline.cpp119
-rw-r--r--source/Host/common/File.cpp162
-rw-r--r--source/Host/common/FileSpec.cpp412
-rw-r--r--source/Host/common/FileSystem.cpp103
-rw-r--r--source/Host/common/Host.cpp180
-rw-r--r--source/Host/common/HostInfoBase.cpp82
-rw-r--r--source/Host/common/LockFileBase.cpp124
-rw-r--r--source/Host/common/NativeBreakpointList.cpp22
-rw-r--r--source/Host/common/NativeProcessProtocol.cpp6
-rw-r--r--source/Host/common/NativeRegisterContext.cpp58
-rw-r--r--source/Host/common/Socket.cpp89
-rw-r--r--source/Host/common/SocketAddress.cpp11
-rw-r--r--source/Host/common/SoftwareBreakpoint.cpp56
-rw-r--r--source/Host/common/Symbols.cpp306
-rw-r--r--source/Host/common/Terminal.cpp6
-rw-r--r--source/Host/common/XML.cpp693
-rw-r--r--source/Host/freebsd/Host.cpp36
-rw-r--r--source/Host/freebsd/HostThreadFreeBSD.cpp2
-rw-r--r--source/Host/freebsd/ThisThread.cpp9
-rw-r--r--source/Host/posix/ConnectionFileDescriptorPosix.cpp62
-rw-r--r--source/Host/posix/FileSystem.cpp181
-rw-r--r--source/Host/posix/HostInfoPosix.cpp32
-rw-r--r--source/Host/posix/HostProcessPosix.cpp17
-rw-r--r--source/Host/posix/LockFilePosix.cpp77
-rw-r--r--source/Host/posix/PipePosix.cpp24
-rw-r--r--source/Initialization/SystemInitializer.cpp20
-rw-r--r--source/Initialization/SystemInitializerCommon.cpp185
-rw-r--r--source/Initialization/SystemLifetimeManager.cpp61
-rw-r--r--source/Interpreter/Args.cpp385
-rw-r--r--source/Interpreter/CommandInterpreter.cpp475
-rw-r--r--source/Interpreter/CommandObject.cpp70
-rw-r--r--source/Interpreter/CommandObjectRegexCommand.cpp2
-rw-r--r--source/Interpreter/CommandObjectScript.cpp2
-rw-r--r--source/Interpreter/OptionGroupBoolean.cpp2
-rw-r--r--source/Interpreter/OptionGroupFile.cpp4
-rw-r--r--source/Interpreter/OptionGroupFormat.cpp8
-rw-r--r--source/Interpreter/OptionGroupOutputFile.cpp4
-rw-r--r--source/Interpreter/OptionGroupPlatform.cpp2
-rw-r--r--source/Interpreter/OptionGroupString.cpp2
-rw-r--r--source/Interpreter/OptionGroupUInt64.cpp2
-rw-r--r--source/Interpreter/OptionGroupUUID.cpp2
-rw-r--r--source/Interpreter/OptionGroupValueObjectDisplay.cpp2
-rw-r--r--source/Interpreter/OptionGroupVariable.cpp2
-rw-r--r--source/Interpreter/OptionGroupWatchpoint.cpp4
-rw-r--r--source/Interpreter/OptionValue.cpp43
-rw-r--r--source/Interpreter/OptionValueArch.cpp19
-rw-r--r--source/Interpreter/OptionValueArray.cpp12
-rw-r--r--source/Interpreter/OptionValueBoolean.cpp13
-rw-r--r--source/Interpreter/OptionValueChar.cpp8
-rw-r--r--source/Interpreter/OptionValueDictionary.cpp22
-rw-r--r--source/Interpreter/OptionValueEnumeration.cpp15
-rw-r--r--source/Interpreter/OptionValueFileSpec.cpp46
-rw-r--r--source/Interpreter/OptionValueFileSpecLIst.cpp6
-rw-r--r--source/Interpreter/OptionValueFormat.cpp8
-rw-r--r--source/Interpreter/OptionValueFormatEntity.cpp30
-rw-r--r--source/Interpreter/OptionValueLanguage.cpp73
-rw-r--r--source/Interpreter/OptionValuePathMappings.cpp6
-rw-r--r--source/Interpreter/OptionValueProperties.cpp6
-rw-r--r--source/Interpreter/OptionValueRegex.cpp6
-rw-r--r--source/Interpreter/OptionValueSInt64.cpp11
-rw-r--r--source/Interpreter/OptionValueString.cpp32
-rw-r--r--source/Interpreter/OptionValueUInt64.cpp11
-rw-r--r--source/Interpreter/OptionValueUUID.cpp10
-rw-r--r--source/Interpreter/Options.cpp4
-rw-r--r--source/Interpreter/Property.cpp27
-rw-r--r--source/Interpreter/PythonDataObjects.cpp143
-rw-r--r--source/Interpreter/ScriptInterpreter.cpp57
-rw-r--r--source/Interpreter/ScriptInterpreterNone.cpp2
-rw-r--r--source/Interpreter/ScriptInterpreterPython.cpp864
-rw-r--r--source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp27
-rw-r--r--source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp24
-rw-r--r--source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp12
-rw-r--r--source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp916
-rw-r--r--source/Plugins/ABI/SysV-arm/ABISysV_arm.h121
-rw-r--r--source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp1081
-rw-r--r--source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h125
-rw-r--r--source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp13
-rw-r--r--source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp815
-rw-r--r--source/Plugins/ABI/SysV-i386/ABISysV_i386.h138
-rw-r--r--source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp590
-rw-r--r--source/Plugins/ABI/SysV-mips/ABISysV_mips.h123
-rw-r--r--source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp570
-rw-r--r--source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h133
-rw-r--r--source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp21
-rw-r--r--source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp21
-rw-r--r--source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp24
-rw-r--r--source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp105
-rw-r--r--source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h2
-rw-r--r--source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp4
-rw-r--r--source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp1
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp60
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h23
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp102
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h6
-rw-r--r--source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp441
-rw-r--r--source/Plugins/Instruction/ARM/EmulationStateARM.cpp2
-rw-r--r--source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp389
-rw-r--r--source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h43
-rw-r--r--source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp2918
-rw-r--r--source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h313
-rw-r--r--source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp2920
-rw-r--r--source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h313
-rw-r--r--source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp55
-rw-r--r--source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp9
-rw-r--r--source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp51
-rw-r--r--source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h6
-rw-r--r--source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp1191
-rw-r--r--source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h232
-rw-r--r--source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp7
-rw-r--r--source/Plugins/ObjectFile/ELF/ELFHeader.cpp5
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp451
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.h94
-rw-r--r--source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp1
-rw-r--r--source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp184
-rw-r--r--source/Plugins/OperatingSystem/Python/OperatingSystemPython.h23
-rw-r--r--source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp445
-rw-r--r--source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h303
-rw-r--r--source/Plugins/Platform/POSIX/PlatformPOSIX.cpp91
-rw-r--r--source/Plugins/Platform/POSIX/PlatformPOSIX.h84
-rw-r--r--source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp319
-rw-r--r--source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h232
-rw-r--r--source/Plugins/Process/FreeBSD/FreeBSDThread.cpp1
-rw-r--r--source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp (renamed from source/Plugins/Process/POSIX/POSIXStopInfo.cpp)0
-rw-r--r--source/Plugins/Process/FreeBSD/POSIXStopInfo.h (renamed from source/Plugins/Process/POSIX/POSIXStopInfo.h)0
-rw-r--r--source/Plugins/Process/FreeBSD/POSIXThread.cpp (renamed from source/Plugins/Process/POSIX/POSIXThread.cpp)70
-rw-r--r--source/Plugins/Process/FreeBSD/POSIXThread.h (renamed from source/Plugins/Process/POSIX/POSIXThread.h)33
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp19
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.cpp68
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.h35
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp (renamed from source/Plugins/Process/POSIX/ProcessPOSIX.cpp)177
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessPOSIX.h (renamed from source/Plugins/Process/POSIX/ProcessPOSIX.h)68
-rw-r--r--source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp322
-rw-r--r--source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h95
-rw-r--r--source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp)8
-rw-r--r--source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h)0
-rw-r--r--source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp)5
-rw-r--r--source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h)0
-rw-r--r--source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp)3
-rw-r--r--source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h)0
-rw-r--r--source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp)9
-rw-r--r--source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h)0
-rw-r--r--source/Plugins/Process/POSIX/CrashReason.cpp42
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp19
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIXLog.h6
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.cpp629
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.h14
-rw-r--r--source/Plugins/Process/Utility/FreeBSDSignals.cpp70
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.cpp9
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.h5
-rw-r--r--source/Plugins/Process/Utility/LinuxSignals.cpp103
-rw-r--r--source/Plugins/Process/Utility/LinuxSignals.h8
-rw-r--r--source/Plugins/Process/Utility/MipsLinuxSignals.cpp95
-rw-r--r--source/Plugins/Process/Utility/MipsLinuxSignals.h37
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp88
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h75
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp86
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h78
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp7
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp25
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.cpp192
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp87
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_arm.h76
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp3
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp102
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_mips.h32
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp143
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_mips64.h40
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp13
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp287
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h121
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp3
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h159
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h54
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp3
-rw-r--r--source/Plugins/Process/Utility/RegisterContext_mips64.h232
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_arm.h303
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_arm64.h16
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_i386.h14
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_mips.h122
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_mips64.h86
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_x86_64.h17
-rw-r--r--source/Plugins/Process/Utility/StopInfoMachException.cpp7
-rw-r--r--source/Plugins/Process/Utility/ThreadMemory.cpp2
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.cpp1
-rw-r--r--source/Plugins/Process/Utility/lldb-arm-register-enums.h153
-rw-r--r--source/Plugins/Process/Utility/lldb-arm64-register-enums.h172
-rw-r--r--source/Plugins/Process/Utility/lldb-mips64-register-enums.h199
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.cpp18
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.h39
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp94
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h60
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp94
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h60
-rw-r--r--source/Plugins/Process/elf-core/ThreadElfCore.cpp24
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp655
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h126
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp1095
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h239
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp4458
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h523
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp1341
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h216
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp2787
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h307
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp376
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h102
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp22
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h77
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp2292
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.h243
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp19
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h21
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp60
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.h74
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp56
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h8
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp22
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp65
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h8
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp2
-rw-r--r--source/Plugins/SymbolFile/DWARF/NameToDIE.cpp2
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp388
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h53
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp244
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h105
-rw-r--r--source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp8
-rw-r--r--source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h3
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp226
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h11
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp143
-rw-r--r--source/Symbol/Block.cpp2
-rw-r--r--source/Symbol/ClangASTContext.cpp54
-rw-r--r--source/Symbol/ClangASTImporter.cpp12
-rw-r--r--source/Symbol/ClangASTType.cpp97
-rw-r--r--source/Symbol/ClangExternalASTSourceCallbacks.cpp13
-rw-r--r--source/Symbol/CompactUnwindInfo.cpp77
-rw-r--r--source/Symbol/CompileUnit.cpp25
-rw-r--r--source/Symbol/DWARFCallFrameInfo.cpp590
-rw-r--r--source/Symbol/FuncUnwinders.cpp57
-rw-r--r--source/Symbol/LineTable.cpp3
-rw-r--r--source/Symbol/ObjectFile.cpp3
-rw-r--r--source/Symbol/Symbol.cpp62
-rw-r--r--source/Symbol/SymbolContext.cpp47
-rw-r--r--source/Symbol/SymbolVendor.cpp31
-rw-r--r--source/Symbol/Symtab.cpp62
-rw-r--r--source/Symbol/Type.cpp23
-rw-r--r--source/Symbol/UnwindPlan.cpp141
-rw-r--r--source/Symbol/Variable.cpp13
-rw-r--r--source/Target/ABI.cpp1
-rw-r--r--source/Target/ExecutionContext.cpp35
-rw-r--r--source/Target/FileAction.cpp23
-rw-r--r--source/Target/LanguageRuntime.cpp84
-rw-r--r--source/Target/Memory.cpp139
-rw-r--r--source/Target/ObjCLanguageRuntime.cpp47
-rw-r--r--source/Target/Platform.cpp498
-rw-r--r--source/Target/Process.cpp570
-rw-r--r--source/Target/ProcessLaunchInfo.cpp119
-rw-r--r--source/Target/StackFrame.cpp8
-rw-r--r--source/Target/StackFrameList.cpp17
-rw-r--r--source/Target/StopInfo.cpp48
-rw-r--r--source/Target/Target.cpp567
-rw-r--r--source/Target/TargetList.cpp43
-rw-r--r--source/Target/Thread.cpp37
-rw-r--r--source/Target/ThreadList.cpp6
-rw-r--r--source/Target/ThreadPlan.cpp4
-rw-r--r--source/Target/ThreadPlanCallFunction.cpp4
-rw-r--r--source/Target/ThreadPlanCallUserExpression.cpp4
-rw-r--r--source/Target/ThreadPlanPython.cpp3
-rw-r--r--source/Target/ThreadPlanRunToAddress.cpp1
-rw-r--r--source/Target/ThreadPlanStepInRange.cpp3
-rw-r--r--source/Target/ThreadPlanStepInstruction.cpp1
-rw-r--r--source/Target/ThreadPlanStepOut.cpp2
-rw-r--r--source/Target/ThreadPlanStepOverBreakpoint.cpp1
-rw-r--r--source/Target/ThreadPlanStepOverRange.cpp6
-rw-r--r--source/Target/ThreadPlanStepRange.cpp9
-rw-r--r--source/Target/ThreadPlanStepThrough.cpp1
-rw-r--r--source/Target/ThreadPlanStepUntil.cpp1
-rw-r--r--source/Target/ThreadPlanTracer.cpp8
-rw-r--r--source/Utility/ConvertEnum.cpp110
-rw-r--r--source/Utility/JSON.cpp217
-rw-r--r--source/Utility/LLDBAssert.cpp36
-rw-r--r--source/Utility/ModuleCache.cpp186
-rw-r--r--source/Utility/ModuleCache.h78
-rw-r--r--source/Utility/NameMatches.cpp50
-rw-r--r--source/Utility/PseudoTerminal.cpp12
-rw-r--r--source/Utility/StringExtractor.cpp4
-rw-r--r--source/Utility/StringExtractorGDBRemote.cpp13
-rw-r--r--source/Utility/StringExtractorGDBRemote.h4
-rw-r--r--source/Utility/UriParser.cpp1
-rw-r--r--source/lldb.cpp402
-rw-r--r--tools/argdumper/argdumper.cpp38
-rw-r--r--tools/argdumper/exports0
-rw-r--r--tools/compact-unwind/compact-unwind-dumper.c2
-rw-r--r--tools/driver/Driver.cpp43
-rw-r--r--tools/driver/Platform.h15
-rw-r--r--tools/lldb-mi/Driver.cpp1276
-rw-r--r--tools/lldb-mi/Driver.h144
-rw-r--r--tools/lldb-mi/MICmdArgContext.cpp42
-rw-r--r--tools/lldb-mi/MICmdArgContext.h14
-rw-r--r--tools/lldb-mi/MICmdArgSet.cpp35
-rw-r--r--tools/lldb-mi/MICmdArgSet.h12
-rw-r--r--tools/lldb-mi/MICmdArgValBase.cpp12
-rw-r--r--tools/lldb-mi/MICmdArgValBase.h14
-rw-r--r--tools/lldb-mi/MICmdArgValConsume.cpp24
-rw-r--r--tools/lldb-mi/MICmdArgValConsume.h12
-rw-r--r--tools/lldb-mi/MICmdArgValFile.cpp29
-rw-r--r--tools/lldb-mi/MICmdArgValFile.h12
-rw-r--r--tools/lldb-mi/MICmdArgValListBase.cpp12
-rw-r--r--tools/lldb-mi/MICmdArgValListBase.h12
-rw-r--r--tools/lldb-mi/MICmdArgValListOfN.cpp14
-rw-r--r--tools/lldb-mi/MICmdArgValListOfN.h22
-rw-r--r--tools/lldb-mi/MICmdArgValNumber.cpp41
-rw-r--r--tools/lldb-mi/MICmdArgValNumber.h29
-rw-r--r--tools/lldb-mi/MICmdArgValOptionLong.cpp16
-rw-r--r--tools/lldb-mi/MICmdArgValOptionLong.h12
-rw-r--r--tools/lldb-mi/MICmdArgValOptionShort.cpp12
-rw-r--r--tools/lldb-mi/MICmdArgValOptionShort.h12
-rw-r--r--tools/lldb-mi/MICmdArgValPrintValues.cpp129
-rw-r--r--tools/lldb-mi/MICmdArgValPrintValues.h53
-rw-r--r--tools/lldb-mi/MICmdArgValString.cpp238
-rw-r--r--tools/lldb-mi/MICmdArgValString.h14
-rw-r--r--tools/lldb-mi/MICmdArgValThreadGrp.cpp14
-rw-r--r--tools/lldb-mi/MICmdArgValThreadGrp.h12
-rw-r--r--tools/lldb-mi/MICmdBase.cpp12
-rw-r--r--tools/lldb-mi/MICmdBase.h12
-rw-r--r--tools/lldb-mi/MICmdCmd.cpp10
-rw-r--r--tools/lldb-mi/MICmdCmd.h10
-rw-r--r--tools/lldb-mi/MICmdCmdBreak.cpp49
-rw-r--r--tools/lldb-mi/MICmdCmdBreak.h10
-rw-r--r--tools/lldb-mi/MICmdCmdData.cpp390
-rw-r--r--tools/lldb-mi/MICmdCmdData.h58
-rw-r--r--tools/lldb-mi/MICmdCmdEnviro.cpp10
-rw-r--r--tools/lldb-mi/MICmdCmdEnviro.h10
-rw-r--r--tools/lldb-mi/MICmdCmdExec.cpp245
-rw-r--r--tools/lldb-mi/MICmdCmdExec.h68
-rw-r--r--tools/lldb-mi/MICmdCmdFile.cpp44
-rw-r--r--tools/lldb-mi/MICmdCmdFile.h15
-rw-r--r--tools/lldb-mi/MICmdCmdGdbInfo.cpp15
-rw-r--r--tools/lldb-mi/MICmdCmdGdbInfo.h10
-rw-r--r--tools/lldb-mi/MICmdCmdGdbSet.cpp180
-rw-r--r--tools/lldb-mi/MICmdCmdGdbSet.h17
-rw-r--r--tools/lldb-mi/MICmdCmdGdbShow.cpp340
-rw-r--r--tools/lldb-mi/MICmdCmdGdbShow.h86
-rw-r--r--tools/lldb-mi/MICmdCmdGdbThread.cpp10
-rw-r--r--tools/lldb-mi/MICmdCmdGdbThread.h10
-rw-r--r--tools/lldb-mi/MICmdCmdMiscellanous.cpp27
-rw-r--r--tools/lldb-mi/MICmdCmdMiscellanous.h10
-rw-r--r--tools/lldb-mi/MICmdCmdStack.cpp501
-rw-r--r--tools/lldb-mi/MICmdCmdStack.h113
-rw-r--r--tools/lldb-mi/MICmdCmdSupportInfo.cpp10
-rw-r--r--tools/lldb-mi/MICmdCmdSupportInfo.h10
-rw-r--r--tools/lldb-mi/MICmdCmdSupportList.cpp10
-rw-r--r--tools/lldb-mi/MICmdCmdSupportList.h10
-rw-r--r--tools/lldb-mi/MICmdCmdSymbol.cpp173
-rw-r--r--tools/lldb-mi/MICmdCmdSymbol.h57
-rw-r--r--tools/lldb-mi/MICmdCmdTarget.cpp275
-rw-r--r--tools/lldb-mi/MICmdCmdTarget.h69
-rw-r--r--tools/lldb-mi/MICmdCmdThread.cpp20
-rw-r--r--tools/lldb-mi/MICmdCmdThread.h10
-rw-r--r--tools/lldb-mi/MICmdCmdTrace.cpp10
-rw-r--r--tools/lldb-mi/MICmdCmdTrace.h10
-rw-r--r--tools/lldb-mi/MICmdCmdVar.cpp425
-rw-r--r--tools/lldb-mi/MICmdCmdVar.h45
-rw-r--r--tools/lldb-mi/MICmdCommands.cpp22
-rw-r--r--tools/lldb-mi/MICmdCommands.h12
-rw-r--r--tools/lldb-mi/MICmdData.cpp12
-rw-r--r--tools/lldb-mi/MICmdData.h12
-rw-r--r--tools/lldb-mi/MICmdFactory.cpp16
-rw-r--r--tools/lldb-mi/MICmdFactory.h12
-rw-r--r--tools/lldb-mi/MICmdInterpreter.cpp42
-rw-r--r--tools/lldb-mi/MICmdInterpreter.h14
-rw-r--r--tools/lldb-mi/MICmdInvoker.cpp12
-rw-r--r--tools/lldb-mi/MICmdInvoker.h12
-rw-r--r--tools/lldb-mi/MICmdMgr.cpp12
-rw-r--r--tools/lldb-mi/MICmdMgr.h12
-rw-r--r--tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.cpp12
-rw-r--r--tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.h12
-rw-r--r--tools/lldb-mi/MICmnBase.cpp12
-rw-r--r--tools/lldb-mi/MICmnBase.h12
-rw-r--r--tools/lldb-mi/MICmnConfig.h32
-rw-r--r--tools/lldb-mi/MICmnLLDBBroadcaster.cpp12
-rw-r--r--tools/lldb-mi/MICmnLLDBBroadcaster.h12
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp913
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugSessionInfo.h78
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.cpp92
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.h23
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugger.cpp144
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugger.h21
-rw-r--r--tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp777
-rw-r--r--tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h36
-rw-r--r--tools/lldb-mi/MICmnLLDBProxySBValue.cpp20
-rw-r--r--tools/lldb-mi/MICmnLLDBProxySBValue.h12
-rw-r--r--tools/lldb-mi/MICmnLLDBUtilSBValue.cpp430
-rw-r--r--tools/lldb-mi/MICmnLLDBUtilSBValue.h40
-rw-r--r--tools/lldb-mi/MICmnLog.cpp12
-rw-r--r--tools/lldb-mi/MICmnLog.h12
-rw-r--r--tools/lldb-mi/MICmnLogMediumFile.cpp75
-rw-r--r--tools/lldb-mi/MICmnLogMediumFile.h19
-rw-r--r--tools/lldb-mi/MICmnMIOutOfBandRecord.cpp52
-rw-r--r--tools/lldb-mi/MICmnMIOutOfBandRecord.h21
-rw-r--r--tools/lldb-mi/MICmnMIResultRecord.cpp14
-rw-r--r--tools/lldb-mi/MICmnMIResultRecord.h12
-rw-r--r--tools/lldb-mi/MICmnMIValue.cpp12
-rw-r--r--tools/lldb-mi/MICmnMIValue.h12
-rw-r--r--tools/lldb-mi/MICmnMIValueConst.cpp16
-rw-r--r--tools/lldb-mi/MICmnMIValueConst.h12
-rw-r--r--tools/lldb-mi/MICmnMIValueList.cpp25
-rw-r--r--tools/lldb-mi/MICmnMIValueList.h12
-rw-r--r--tools/lldb-mi/MICmnMIValueResult.cpp18
-rw-r--r--tools/lldb-mi/MICmnMIValueResult.h14
-rw-r--r--tools/lldb-mi/MICmnMIValueTuple.cpp24
-rw-r--r--tools/lldb-mi/MICmnMIValueTuple.h14
-rw-r--r--tools/lldb-mi/MICmnResources.cpp64
-rw-r--r--tools/lldb-mi/MICmnResources.h44
-rw-r--r--tools/lldb-mi/MICmnStreamStderr.cpp12
-rw-r--r--tools/lldb-mi/MICmnStreamStderr.h12
-rw-r--r--tools/lldb-mi/MICmnStreamStdin.cpp302
-rw-r--r--tools/lldb-mi/MICmnStreamStdin.h72
-rw-r--r--tools/lldb-mi/MICmnStreamStdinLinux.cpp225
-rw-r--r--tools/lldb-mi/MICmnStreamStdinLinux.h72
-rw-r--r--tools/lldb-mi/MICmnStreamStdinWindows.cpp285
-rw-r--r--tools/lldb-mi/MICmnStreamStdinWindows.h79
-rw-r--r--tools/lldb-mi/MICmnStreamStdout.cpp40
-rw-r--r--tools/lldb-mi/MICmnStreamStdout.h13
-rw-r--r--tools/lldb-mi/MICmnThreadMgrStd.cpp12
-rw-r--r--tools/lldb-mi/MICmnThreadMgrStd.h12
-rw-r--r--tools/lldb-mi/MIDataTypes.h13
-rw-r--r--tools/lldb-mi/MIDriver.cpp503
-rw-r--r--tools/lldb-mi/MIDriver.h33
-rw-r--r--tools/lldb-mi/MIDriverBase.cpp12
-rw-r--r--tools/lldb-mi/MIDriverBase.h12
-rw-r--r--tools/lldb-mi/MIDriverMain.cpp235
-rw-r--r--tools/lldb-mi/MIDriverMgr.cpp116
-rw-r--r--tools/lldb-mi/MIDriverMgr.h16
-rw-r--r--tools/lldb-mi/MIExtensions.txt103
-rw-r--r--tools/lldb-mi/MIReadMe.txt254
-rw-r--r--tools/lldb-mi/MIUtilDateTimeStd.cpp30
-rw-r--r--tools/lldb-mi/MIUtilDateTimeStd.h15
-rw-r--r--tools/lldb-mi/MIUtilDebug.cpp12
-rw-r--r--tools/lldb-mi/MIUtilDebug.h12
-rw-r--r--tools/lldb-mi/MIUtilFileStd.cpp28
-rw-r--r--tools/lldb-mi/MIUtilFileStd.h18
-rw-r--r--tools/lldb-mi/MIUtilMapIdToVariant.cpp12
-rw-r--r--tools/lldb-mi/MIUtilMapIdToVariant.h12
-rw-r--r--tools/lldb-mi/MIUtilSingletonBase.h12
-rw-r--r--tools/lldb-mi/MIUtilSingletonHelper.h12
-rw-r--r--tools/lldb-mi/MIUtilString.cpp583
-rw-r--r--tools/lldb-mi/MIUtilString.h44
-rw-r--r--tools/lldb-mi/MIUtilSystemLinux.cpp14
-rw-r--r--tools/lldb-mi/MIUtilSystemLinux.h14
-rw-r--r--tools/lldb-mi/MIUtilSystemOsx.cpp12
-rw-r--r--tools/lldb-mi/MIUtilSystemOsx.h12
-rw-r--r--tools/lldb-mi/MIUtilSystemWindows.cpp26
-rw-r--r--tools/lldb-mi/MIUtilSystemWindows.h12
-rw-r--r--tools/lldb-mi/MIUtilTermios.cpp71
-rw-r--r--tools/lldb-mi/MIUtilTermios.h30
-rw-r--r--tools/lldb-mi/MIUtilThreadBaseStd.cpp43
-rw-r--r--tools/lldb-mi/MIUtilThreadBaseStd.h15
-rw-r--r--tools/lldb-mi/MIUtilVariant.cpp12
-rw-r--r--tools/lldb-mi/MIUtilVariant.h12
-rw-r--r--tools/lldb-mi/Platform.cpp61
-rw-r--r--tools/lldb-mi/Platform.h8
-rw-r--r--tools/lldb-server/LLDBServerUtilities.cpp67
-rw-r--r--tools/lldb-server/LLDBServerUtilities.h25
-rw-r--r--tools/lldb-server/exports0
-rw-r--r--tools/lldb-server/lldb-gdbserver.cpp698
-rw-r--r--tools/lldb-server/lldb-platform.cpp (renamed from tools/lldb-platform/lldb-platform.cpp)192
-rw-r--r--tools/lldb-server/lldb-server.cpp76
833 files changed, 57483 insertions, 28839 deletions
diff --git a/include/lldb/API/LLDB.h b/include/lldb/API/LLDB.h
index 4026b2b61ba8..66e095395f13 100644
--- a/include/lldb/API/LLDB.h
+++ b/include/lldb/API/LLDB.h
@@ -52,5 +52,6 @@
#include "lldb/API/SBType.h"
#include "lldb/API/SBValue.h"
#include "lldb/API/SBValueList.h"
+#include "lldb/API/SBVariablesOptions.h"
#endif // LLDB_LLDB_h_
diff --git a/include/lldb/API/SBAddress.h b/include/lldb/API/SBAddress.h
index c2d07b6e9bcc..4cbbee9fd132 100644
--- a/include/lldb/API/SBAddress.h
+++ b/include/lldb/API/SBAddress.h
@@ -15,7 +15,7 @@
namespace lldb {
-class SBAddress
+class LLDB_API SBAddress
{
public:
diff --git a/include/lldb/API/SBAttachInfo.h b/include/lldb/API/SBAttachInfo.h
new file mode 100644
index 000000000000..712150e128be
--- /dev/null
+++ b/include/lldb/API/SBAttachInfo.h
@@ -0,0 +1,149 @@
+//===-- SBAttachInfo.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_SBAttachInfo_h_
+#define LLDB_SBAttachInfo_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBTarget;
+
+class LLDB_API SBAttachInfo
+{
+public:
+ SBAttachInfo ();
+
+ SBAttachInfo (lldb::pid_t pid);
+
+ SBAttachInfo (const char *path, bool wait_for);
+
+ SBAttachInfo (const SBAttachInfo &rhs);
+
+ ~SBAttachInfo();
+
+ SBAttachInfo &
+ operator = (const SBAttachInfo &rhs);
+
+ lldb::pid_t
+ GetProcessID ();
+
+ void
+ SetProcessID (lldb::pid_t pid);
+
+ void
+ SetExecutable (const char *path);
+
+ void
+ SetExecutable (lldb::SBFileSpec exe_file);
+
+ bool
+ GetWaitForLaunch ();
+
+ void
+ SetWaitForLaunch (bool b);
+
+ bool
+ GetIgnoreExisting ();
+
+ void
+ SetIgnoreExisting (bool b);
+
+ uint32_t
+ GetResumeCount ();
+
+ void
+ SetResumeCount (uint32_t c);
+
+ const char *
+ GetProcessPluginName ();
+
+ void
+ SetProcessPluginName (const char *plugin_name);
+
+ uint32_t
+ GetUserID();
+
+ uint32_t
+ GetGroupID();
+
+ bool
+ UserIDIsValid ();
+
+ bool
+ GroupIDIsValid ();
+
+ void
+ SetUserID (uint32_t uid);
+
+ void
+ SetGroupID (uint32_t gid);
+
+ uint32_t
+ GetEffectiveUserID();
+
+ uint32_t
+ GetEffectiveGroupID();
+
+ bool
+ EffectiveUserIDIsValid ();
+
+ bool
+ EffectiveGroupIDIsValid ();
+
+ void
+ SetEffectiveUserID (uint32_t uid);
+
+ void
+ SetEffectiveGroupID (uint32_t gid);
+
+ lldb::pid_t
+ GetParentProcessID ();
+
+ void
+ SetParentProcessID (lldb::pid_t pid);
+
+ bool
+ ParentProcessIDIsValid();
+
+ //----------------------------------------------------------------------
+ /// Get the listener that will be used to receive process events.
+ ///
+ /// If no listener has been set via a call to
+ /// SBLaunchInfo::SetListener(), then an invalid SBListener will be
+ /// returned (SBListener::IsValid() will return false). If a listener
+ /// has been set, then the valid listener object will be returned.
+ //----------------------------------------------------------------------
+ SBListener
+ GetListener ();
+
+ //----------------------------------------------------------------------
+ /// Set the listener that will be used to receive process events.
+ ///
+ /// By default the SBDebugger, which has a listener, that the SBTarget
+ /// belongs to will listen for the process events. Calling this function
+ /// allows a different listener to be used to listen for process events.
+ //----------------------------------------------------------------------
+ void
+ SetListener (SBListener &listener);
+
+
+protected:
+ friend class SBTarget;
+
+ lldb_private::ProcessAttachInfo &
+ ref ();
+
+ ProcessAttachInfoSP m_opaque_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBAttachInfo_h_
diff --git a/include/lldb/API/SBBlock.h b/include/lldb/API/SBBlock.h
index b8e61fc6eb27..a18eab02088b 100644
--- a/include/lldb/API/SBBlock.h
+++ b/include/lldb/API/SBBlock.h
@@ -17,7 +17,7 @@
namespace lldb {
-class SBBlock
+class LLDB_API SBBlock
{
public:
diff --git a/include/lldb/API/SBBreakpoint.h b/include/lldb/API/SBBreakpoint.h
index 20a97a1fb5a0..c244ab8a9b48 100644
--- a/include/lldb/API/SBBreakpoint.h
+++ b/include/lldb/API/SBBreakpoint.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBBreakpoint
+class LLDB_API SBBreakpoint
{
public:
diff --git a/include/lldb/API/SBBreakpointLocation.h b/include/lldb/API/SBBreakpointLocation.h
index fd9f246de4ff..ab7049739c0b 100644
--- a/include/lldb/API/SBBreakpointLocation.h
+++ b/include/lldb/API/SBBreakpointLocation.h
@@ -15,7 +15,7 @@
namespace lldb {
-class SBBreakpointLocation
+class LLDB_API SBBreakpointLocation
{
public:
@@ -101,9 +101,7 @@ public:
private:
friend class SBBreakpoint;
-#ifndef LLDB_DISABLE_PYTHON
- friend class lldb_private::ScriptInterpreterPython;
-#endif
+
void
SetLocation (const lldb::BreakpointLocationSP &break_loc_sp);
diff --git a/include/lldb/API/SBBroadcaster.h b/include/lldb/API/SBBroadcaster.h
index 7b32d85faa0f..28b6686b79b3 100644
--- a/include/lldb/API/SBBroadcaster.h
+++ b/include/lldb/API/SBBroadcaster.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBBroadcaster
+class LLDB_API SBBroadcaster
{
public:
SBBroadcaster ();
diff --git a/include/lldb/API/SBCommandInterpreter.h b/include/lldb/API/SBCommandInterpreter.h
index 947e39164140..235a2f3ea603 100644
--- a/include/lldb/API/SBCommandInterpreter.h
+++ b/include/lldb/API/SBCommandInterpreter.h
@@ -15,7 +15,7 @@
namespace lldb {
-class SBCommandInterpreterRunOptions
+class LLDB_API SBCommandInterpreterRunOptions
{
friend class SBDebugger;
friend class SBCommandInterpreter;
@@ -94,6 +94,9 @@ public:
static const char *
GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type);
+
+ static bool
+ EventIsCommandInterpreterEvent (const lldb::SBEvent &event);
bool
IsValid() const;
@@ -216,6 +219,19 @@ public:
const char *
GetIOHandlerControlSequence(char ch);
+ bool
+ GetPromptOnQuit();
+
+ void
+ SetPromptOnQuit(bool b);
+
+ //----------------------------------------------------------------------
+ /// Resolve the command just as HandleCommand would, expanding abbreviations
+ /// and aliases. If successful, result->GetOutput has the full expansion.
+ //----------------------------------------------------------------------
+ void
+ ResolveCommand(const char *command_line, SBCommandReturnObject &result);
+
protected:
lldb_private::CommandInterpreter &
@@ -266,6 +282,21 @@ public:
const char*
GetHelp ();
+ const char*
+ GetHelpLong ();
+
+ void
+ SetHelp (const char*);
+
+ void
+ SetHelpLong (const char*);
+
+ uint32_t
+ GetFlags ();
+
+ void
+ SetFlags (uint32_t flags);
+
lldb::SBCommand
AddMultiwordCommand (const char* name, const char* help = NULL);
diff --git a/include/lldb/API/SBCommandReturnObject.h b/include/lldb/API/SBCommandReturnObject.h
index f2d274802330..c51d6bc8d2d5 100644
--- a/include/lldb/API/SBCommandReturnObject.h
+++ b/include/lldb/API/SBCommandReturnObject.h
@@ -16,7 +16,7 @@
namespace lldb {
-class SBCommandReturnObject
+class LLDB_API SBCommandReturnObject
{
public:
diff --git a/include/lldb/API/SBCommunication.h b/include/lldb/API/SBCommunication.h
index ecaaa3523c91..c4b2709de8ab 100644
--- a/include/lldb/API/SBCommunication.h
+++ b/include/lldb/API/SBCommunication.h
@@ -15,10 +15,11 @@
namespace lldb {
-class SBCommunication
+class LLDB_API SBCommunication
{
public:
- enum {
+ FLAGS_ANONYMOUS_ENUM()
+ {
eBroadcastBitDisconnected = (1 << 0), ///< Sent when the communications connection is lost.
eBroadcastBitReadThreadGotBytes = (1 << 1), ///< Sent by the read thread when bytes become available.
eBroadcastBitReadThreadDidExit = (1 << 2), ///< Sent by the read thread when it exits to inform clients.
diff --git a/include/lldb/API/SBCompileUnit.h b/include/lldb/API/SBCompileUnit.h
index e2c216445d94..a53d556679c4 100644
--- a/include/lldb/API/SBCompileUnit.h
+++ b/include/lldb/API/SBCompileUnit.h
@@ -15,7 +15,7 @@
namespace lldb {
-class SBCompileUnit
+class LLDB_API SBCompileUnit
{
public:
diff --git a/include/lldb/API/SBData.h b/include/lldb/API/SBData.h
index e7656a52d9c2..a2bd72fad570 100644
--- a/include/lldb/API/SBData.h
+++ b/include/lldb/API/SBData.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBData
+class LLDB_API SBData
{
public:
diff --git a/include/lldb/API/SBDebugger.h b/include/lldb/API/SBDebugger.h
index 6e43e12f7b16..4f2c1d7f8756 100644
--- a/include/lldb/API/SBDebugger.h
+++ b/include/lldb/API/SBDebugger.h
@@ -18,7 +18,7 @@
namespace lldb {
-class SBInputReader
+class LLDB_API SBInputReader
{
public:
SBInputReader();
@@ -28,7 +28,7 @@ public:
bool IsActive() const;
};
-class SBDebugger
+class LLDB_API SBDebugger
{
public:
diff --git a/include/lldb/API/SBDeclaration.h b/include/lldb/API/SBDeclaration.h
index 190026c0d2d0..5461a1f15c2e 100644
--- a/include/lldb/API/SBDeclaration.h
+++ b/include/lldb/API/SBDeclaration.h
@@ -15,7 +15,7 @@
namespace lldb {
- class SBDeclaration
+ class LLDB_API SBDeclaration
{
public:
diff --git a/include/lldb/API/SBDefines.h b/include/lldb/API/SBDefines.h
index b59b79580910..09bea502dd01 100644
--- a/include/lldb/API/SBDefines.h
+++ b/include/lldb/API/SBDefines.h
@@ -55,6 +55,8 @@ class LLDB_API SBFunction;
class LLDB_API SBHostOS;
class LLDB_API SBInstruction;
class LLDB_API SBInstructionList;
+class LLDB_API SBLanguageRuntime;
+class LLDB_API SBLaunchInfo;
class LLDB_API SBLineEntry;
class LLDB_API SBListener;
class LLDB_API SBModule;
@@ -90,6 +92,7 @@ class LLDB_API SBTypeSynthetic;
class LLDB_API SBTypeList;
class LLDB_API SBValue;
class LLDB_API SBValueList;
+class LLDB_API SBVariablesOptions;
class LLDB_API SBWatchpoint;
class LLDB_API SBUnixSignals;
diff --git a/include/lldb/API/SBError.h b/include/lldb/API/SBError.h
index b9908658c5bc..afdec0d3826d 100644
--- a/include/lldb/API/SBError.h
+++ b/include/lldb/API/SBError.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBError {
+class LLDB_API SBError {
public:
SBError ();
diff --git a/include/lldb/API/SBEvent.h b/include/lldb/API/SBEvent.h
index 1706d0c009b9..975c365f5916 100644
--- a/include/lldb/API/SBEvent.h
+++ b/include/lldb/API/SBEvent.h
@@ -20,7 +20,7 @@ namespace lldb {
class SBBroadcaster;
-class SBEvent
+class LLDB_API SBEvent
{
public:
SBEvent();
@@ -78,6 +78,7 @@ protected:
friend class SBBreakpoint;
friend class SBDebugger;
friend class SBProcess;
+ friend class SBTarget;
friend class SBThread;
friend class SBWatchpoint;
diff --git a/include/lldb/API/SBExecutionContext.h b/include/lldb/API/SBExecutionContext.h
index 9d889139f5cb..1d64497ae867 100644
--- a/include/lldb/API/SBExecutionContext.h
+++ b/include/lldb/API/SBExecutionContext.h
@@ -18,7 +18,7 @@
namespace lldb {
-class SBExecutionContext
+class LLDB_API SBExecutionContext
{
friend class SBCommandInterpreter;
diff --git a/include/lldb/API/SBExpressionOptions.h b/include/lldb/API/SBExpressionOptions.h
index c3592880c46a..ed2f9187b3e0 100644
--- a/include/lldb/API/SBExpressionOptions.h
+++ b/include/lldb/API/SBExpressionOptions.h
@@ -17,7 +17,7 @@
namespace lldb {
-class SBExpressionOptions
+class LLDB_API SBExpressionOptions
{
public:
SBExpressionOptions();
@@ -105,6 +105,12 @@ public:
void
SetSuppressPersistentResult (bool b = false);
+ const char *
+ GetPrefix () const;
+
+ void
+ SetPrefix (const char *prefix);
+
protected:
SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options);
diff --git a/include/lldb/API/SBFileSpec.h b/include/lldb/API/SBFileSpec.h
index 1eee3d10367c..d6f38f5b2d74 100644
--- a/include/lldb/API/SBFileSpec.h
+++ b/include/lldb/API/SBFileSpec.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBFileSpec
+class LLDB_API SBFileSpec
{
public:
SBFileSpec ();
diff --git a/include/lldb/API/SBFileSpecList.h b/include/lldb/API/SBFileSpecList.h
index 734e7d4d35cc..ff429a1815be 100644
--- a/include/lldb/API/SBFileSpecList.h
+++ b/include/lldb/API/SBFileSpecList.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBFileSpecList
+class LLDB_API SBFileSpecList
{
public:
SBFileSpecList ();
diff --git a/include/lldb/API/SBFrame.h b/include/lldb/API/SBFrame.h
index b93e36afecdf..2ca9e062490d 100644
--- a/include/lldb/API/SBFrame.h
+++ b/include/lldb/API/SBFrame.h
@@ -15,7 +15,7 @@
namespace lldb {
-class SBFrame
+class LLDB_API SBFrame
{
public:
SBFrame ();
@@ -25,7 +25,7 @@ public:
const lldb::SBFrame &
operator =(const lldb::SBFrame &rhs);
- ~SBFrame();
+ ~SBFrame();
bool
IsEqual (const lldb::SBFrame &that) const;
@@ -37,6 +37,9 @@ public:
GetFrameID () const;
lldb::addr_t
+ GetCFA () const;
+
+ lldb::addr_t
GetPC () const;
bool
@@ -88,12 +91,18 @@ public:
const char *
GetFunctionName();
+ const char *
+ GetFunctionName() const;
+
/// Return true if this frame represents an inlined function.
///
/// See also GetFunctionName().
bool
IsInlined();
-
+
+ bool
+ IsInlined() const;
+
/// The version that doesn't supply a 'use_dynamic' value will use the
/// target's default.
lldb::SBValue
@@ -157,6 +166,9 @@ public:
lldb::DynamicValueType use_dynamic);
lldb::SBValueList
+ GetVariables (const lldb::SBVariablesOptions& options);
+
+ lldb::SBValueList
GetRegisters ();
lldb::SBValue
@@ -210,9 +222,6 @@ protected:
friend class SBInstruction;
friend class SBThread;
friend class SBValue;
-#ifndef LLDB_DISABLE_PYTHON
- friend class lldb_private::ScriptInterpreterPython;
-#endif
lldb::StackFrameSP
GetFrameSP() const;
diff --git a/include/lldb/API/SBFunction.h b/include/lldb/API/SBFunction.h
index 1b0d53d11736..7d578393eb2c 100644
--- a/include/lldb/API/SBFunction.h
+++ b/include/lldb/API/SBFunction.h
@@ -16,7 +16,7 @@
namespace lldb {
-class SBFunction
+class LLDB_API SBFunction
{
public:
diff --git a/include/lldb/API/SBHostOS.h b/include/lldb/API/SBHostOS.h
index 7ab22caaaad9..d9bc97365632 100644
--- a/include/lldb/API/SBHostOS.h
+++ b/include/lldb/API/SBHostOS.h
@@ -15,7 +15,7 @@
namespace lldb {
-class SBHostOS
+class LLDB_API SBHostOS
{
public:
diff --git a/include/lldb/API/SBInstruction.h b/include/lldb/API/SBInstruction.h
index aad2d87f4f33..c4bded595761 100644
--- a/include/lldb/API/SBInstruction.h
+++ b/include/lldb/API/SBInstruction.h
@@ -20,7 +20,7 @@
namespace lldb {
-class SBInstruction
+class LLDB_API SBInstruction
{
public:
diff --git a/include/lldb/API/SBInstructionList.h b/include/lldb/API/SBInstructionList.h
index 944e144a1480..8ef163796629 100644
--- a/include/lldb/API/SBInstructionList.h
+++ b/include/lldb/API/SBInstructionList.h
@@ -16,7 +16,7 @@
namespace lldb {
-class SBInstructionList
+class LLDB_API SBInstructionList
{
public:
diff --git a/include/lldb/API/SBLanguageRuntime.h b/include/lldb/API/SBLanguageRuntime.h
new file mode 100644
index 000000000000..898604c496fa
--- /dev/null
+++ b/include/lldb/API/SBLanguageRuntime.h
@@ -0,0 +1,29 @@
+//===-- SBLanguageRuntime.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_SBLanguageRuntime_h_
+#define LLDB_SBLanguageRuntime_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBLanguageRuntime
+{
+public:
+ static lldb::LanguageType
+ GetLanguageTypeFromString (const char *string);
+
+ static const char *
+ GetNameForLanguageType (lldb::LanguageType language);
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBLanguageRuntime_h_
diff --git a/include/lldb/API/SBLaunchInfo.h b/include/lldb/API/SBLaunchInfo.h
index a5921ab90d48..68c0f386acde 100644
--- a/include/lldb/API/SBLaunchInfo.h
+++ b/include/lldb/API/SBLaunchInfo.h
@@ -17,7 +17,7 @@ namespace lldb {
class SBPlatform;
class SBTarget;
-class SBLaunchInfo
+class LLDB_API SBLaunchInfo
{
public:
SBLaunchInfo (const char **argv);
@@ -140,7 +140,13 @@ public:
void
SetShell (const char * path);
-
+
+ bool
+ GetShellExpandArguments ();
+
+ void
+ SetShellExpandArguments (bool glob);
+
uint32_t
GetResumeCount ();
@@ -178,6 +184,9 @@ protected:
lldb_private::ProcessLaunchInfo &
ref ();
+ const lldb_private::ProcessLaunchInfo &
+ ref () const;
+
ProcessLaunchInfoSP m_opaque_sp;
};
diff --git a/include/lldb/API/SBLineEntry.h b/include/lldb/API/SBLineEntry.h
index 2d099a297980..8311bbbafc90 100644
--- a/include/lldb/API/SBLineEntry.h
+++ b/include/lldb/API/SBLineEntry.h
@@ -16,7 +16,7 @@
namespace lldb {
-class SBLineEntry
+class LLDB_API SBLineEntry
{
public:
diff --git a/include/lldb/API/SBListener.h b/include/lldb/API/SBListener.h
index 58a8fe9a55b7..924f8109f638 100644
--- a/include/lldb/API/SBListener.h
+++ b/include/lldb/API/SBListener.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBListener
+class LLDB_API SBListener
{
public:
SBListener ();
diff --git a/include/lldb/API/SBModule.h b/include/lldb/API/SBModule.h
index e85654bccc72..4030d2b21797 100644
--- a/include/lldb/API/SBModule.h
+++ b/include/lldb/API/SBModule.h
@@ -18,7 +18,7 @@
namespace lldb {
-class SBModule
+class LLDB_API SBModule
{
public:
@@ -106,7 +106,7 @@ public:
/// or "./usr/lib", then the install path will be resolved using
/// the platform's current working directory as the base path.
///
- /// @param[in]
+ /// @param[in] file
/// A file specification object.
//------------------------------------------------------------------
bool
@@ -318,6 +318,23 @@ public:
GetVersion (uint32_t *versions,
uint32_t num_versions);
+ //------------------------------------------------------------------
+ /// Get accessor for the symbol file specification.
+ ///
+ /// When debugging an object file an additional debug information can
+ /// be provided in separate file. Therefore if you debugging something
+ /// like '/usr/lib/liba.dylib' then debug information can be located
+ /// in folder like '/usr/lib/liba.dylib.dSYM/'.
+ ///
+ /// @return
+ /// A const reference to the file specification object.
+ //------------------------------------------------------------------
+ lldb::SBFileSpec
+ GetSymbolFileSpec() const;
+
+ lldb::SBAddress
+ GetObjectFileHeaderAddress() const;
+
private:
friend class SBAddress;
friend class SBFrame;
diff --git a/include/lldb/API/SBModuleSpec.h b/include/lldb/API/SBModuleSpec.h
index a615e017cbc8..d533de3c7bce 100644
--- a/include/lldb/API/SBModuleSpec.h
+++ b/include/lldb/API/SBModuleSpec.h
@@ -15,7 +15,7 @@
namespace lldb {
-class SBModuleSpec
+class LLDB_API SBModuleSpec
{
public:
diff --git a/include/lldb/API/SBPlatform.h b/include/lldb/API/SBPlatform.h
index 42b2d0492895..db4a754103ca 100644
--- a/include/lldb/API/SBPlatform.h
+++ b/include/lldb/API/SBPlatform.h
@@ -21,7 +21,7 @@ namespace lldb {
class SBLaunchInfo;
- class SBPlatformConnectOptions
+ class LLDB_API SBPlatformConnectOptions
{
public:
SBPlatformConnectOptions (const char *url);
@@ -59,7 +59,7 @@ namespace lldb {
PlatformConnectOptions *m_opaque_ptr;
};
- class SBPlatformShellCommand
+ class LLDB_API SBPlatformShellCommand
{
public:
SBPlatformShellCommand (const char *shell_command);
@@ -104,7 +104,7 @@ namespace lldb {
PlatformShellCommand *m_opaque_ptr;
};
- class SBPlatform
+ class LLDB_API SBPlatform
{
public:
diff --git a/include/lldb/API/SBProcess.h b/include/lldb/API/SBProcess.h
index 3d6e49c4821d..71bca4fc697a 100644
--- a/include/lldb/API/SBProcess.h
+++ b/include/lldb/API/SBProcess.h
@@ -20,13 +20,13 @@ namespace lldb {
class SBEvent;
-class SBProcess
+class LLDB_API SBProcess
{
public:
//------------------------------------------------------------------
/// Broadcaster event bits definitions.
//------------------------------------------------------------------
- enum
+ FLAGS_ANONYMOUS_ENUM()
{
eBroadcastBitStateChanged = (1 << 0),
eBroadcastBitInterrupt = (1 << 1),
@@ -229,7 +229,22 @@ public:
uint32_t
GetStopID(bool include_expression_stops = false);
-
+
+ //------------------------------------------------------------------
+ /// Gets the stop event corresponding to stop ID.
+ //
+ /// Note that it wasn't fully implemented and tracks only the stop
+ /// event for the last natural stop ID.
+ ///
+ /// @param [in] stop_id
+ /// The ID of the stop event to return.
+ ///
+ /// @return
+ /// The stop event corresponding to stop ID.
+ //------------------------------------------------------------------
+ lldb::SBEvent
+ GetStopEventForStopID(uint32_t stop_id);
+
size_t
ReadMemory (addr_t addr, void *buf, size_t size, lldb::SBError &error);
@@ -260,6 +275,9 @@ public:
static lldb::SBProcess
GetProcessFromEvent (const lldb::SBEvent &event);
+
+ static bool
+ GetInterruptedFromEvent (const lldb::SBEvent &event);
static bool
EventIsProcessEvent (const lldb::SBEvent &event);
diff --git a/include/lldb/API/SBQueue.h b/include/lldb/API/SBQueue.h
index fbb1952902f8..2f453cddd5d1 100644
--- a/include/lldb/API/SBQueue.h
+++ b/include/lldb/API/SBQueue.h
@@ -17,7 +17,7 @@
namespace lldb {
-class SBQueue
+class LLDB_API SBQueue
{
public:
SBQueue ();
diff --git a/include/lldb/API/SBQueueItem.h b/include/lldb/API/SBQueueItem.h
index c90f36eeb573..9426a53b2376 100644
--- a/include/lldb/API/SBQueueItem.h
+++ b/include/lldb/API/SBQueueItem.h
@@ -15,7 +15,7 @@
namespace lldb {
-class SBQueueItem
+class LLDB_API SBQueueItem
{
public:
SBQueueItem ();
diff --git a/include/lldb/API/SBSection.h b/include/lldb/API/SBSection.h
index 5a49049502fd..0a22413b5b9c 100644
--- a/include/lldb/API/SBSection.h
+++ b/include/lldb/API/SBSection.h
@@ -15,7 +15,7 @@
namespace lldb {
-class SBSection
+class LLDB_API SBSection
{
public:
diff --git a/include/lldb/API/SBSourceManager.h b/include/lldb/API/SBSourceManager.h
index 5b52c49ff3ee..6e7358f16e77 100644
--- a/include/lldb/API/SBSourceManager.h
+++ b/include/lldb/API/SBSourceManager.h
@@ -16,7 +16,7 @@
namespace lldb {
-class SBSourceManager
+class LLDB_API SBSourceManager
{
public:
SBSourceManager (const SBDebugger &debugger);
diff --git a/include/lldb/API/SBStream.h b/include/lldb/API/SBStream.h
index cd33bfda32ba..2b25cd2c68f2 100644
--- a/include/lldb/API/SBStream.h
+++ b/include/lldb/API/SBStream.h
@@ -16,7 +16,7 @@
namespace lldb {
-class SBStream
+class LLDB_API SBStream
{
public:
diff --git a/include/lldb/API/SBStringList.h b/include/lldb/API/SBStringList.h
index 9d0be6e8a741..e0e58f765c6d 100644
--- a/include/lldb/API/SBStringList.h
+++ b/include/lldb/API/SBStringList.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBStringList
+class LLDB_API SBStringList
{
public:
diff --git a/include/lldb/API/SBSymbol.h b/include/lldb/API/SBSymbol.h
index 0a528a9ac96f..3d259a2c20c6 100644
--- a/include/lldb/API/SBSymbol.h
+++ b/include/lldb/API/SBSymbol.h
@@ -17,7 +17,7 @@
namespace lldb {
-class SBSymbol
+class LLDB_API SBSymbol
{
public:
diff --git a/include/lldb/API/SBSymbolContext.h b/include/lldb/API/SBSymbolContext.h
index fee2d19179d0..24c2ce9a1d6e 100644
--- a/include/lldb/API/SBSymbolContext.h
+++ b/include/lldb/API/SBSymbolContext.h
@@ -20,7 +20,7 @@
namespace lldb {
-class SBSymbolContext
+class LLDB_API SBSymbolContext
{
public:
SBSymbolContext ();
diff --git a/include/lldb/API/SBSymbolContextList.h b/include/lldb/API/SBSymbolContextList.h
index 6cc78e472c6f..79dcccdcbf84 100644
--- a/include/lldb/API/SBSymbolContextList.h
+++ b/include/lldb/API/SBSymbolContextList.h
@@ -15,7 +15,7 @@
namespace lldb {
-class SBSymbolContextList
+class LLDB_API SBSymbolContextList
{
public:
SBSymbolContextList ();
diff --git a/include/lldb/API/SBTarget.h b/include/lldb/API/SBTarget.h
index 322cf04159ff..dcca4e7b3a19 100644
--- a/include/lldb/API/SBTarget.h
+++ b/include/lldb/API/SBTarget.h
@@ -12,6 +12,7 @@
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBAttachInfo.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBFileSpec.h"
#include "lldb/API/SBFileSpecList.h"
@@ -25,135 +26,7 @@ namespace lldb {
class SBPlatform;
-class SBAttachInfo
-{
-public:
- SBAttachInfo ();
-
- SBAttachInfo (lldb::pid_t pid);
-
- SBAttachInfo (const char *path, bool wait_for);
-
- SBAttachInfo (const SBAttachInfo &rhs);
-
- ~SBAttachInfo();
-
- SBAttachInfo &
- operator = (const SBAttachInfo &rhs);
-
- lldb::pid_t
- GetProcessID ();
-
- void
- SetProcessID (lldb::pid_t pid);
-
- void
- SetExecutable (const char *path);
-
- void
- SetExecutable (lldb::SBFileSpec exe_file);
-
- bool
- GetWaitForLaunch ();
-
- void
- SetWaitForLaunch (bool b);
-
- bool
- GetIgnoreExisting ();
-
- void
- SetIgnoreExisting (bool b);
-
- uint32_t
- GetResumeCount ();
-
- void
- SetResumeCount (uint32_t c);
-
- const char *
- GetProcessPluginName ();
-
- void
- SetProcessPluginName (const char *plugin_name);
-
- uint32_t
- GetUserID();
-
- uint32_t
- GetGroupID();
-
- bool
- UserIDIsValid ();
-
- bool
- GroupIDIsValid ();
-
- void
- SetUserID (uint32_t uid);
-
- void
- SetGroupID (uint32_t gid);
-
- uint32_t
- GetEffectiveUserID();
-
- uint32_t
- GetEffectiveGroupID();
-
- bool
- EffectiveUserIDIsValid ();
-
- bool
- EffectiveGroupIDIsValid ();
-
- void
- SetEffectiveUserID (uint32_t uid);
-
- void
- SetEffectiveGroupID (uint32_t gid);
-
- lldb::pid_t
- GetParentProcessID ();
-
- void
- SetParentProcessID (lldb::pid_t pid);
-
- bool
- ParentProcessIDIsValid();
-
- //----------------------------------------------------------------------
- /// Get the listener that will be used to receive process events.
- ///
- /// If no listener has been set via a call to
- /// SBLaunchInfo::SetListener(), then an invalid SBListener will be
- /// returned (SBListener::IsValid() will return false). If a listener
- /// has been set, then the valid listener object will be returned.
- //----------------------------------------------------------------------
- SBListener
- GetListener ();
-
- //----------------------------------------------------------------------
- /// Set the listener that will be used to receive process events.
- ///
- /// By default the SBDebugger, which has a listener, that the SBTarget
- /// belongs to will listen for the process events. Calling this function
- /// allows a different listener to be used to listen for process events.
- //----------------------------------------------------------------------
- void
- SetListener (SBListener &listener);
-
-
-protected:
- friend class SBTarget;
-
- lldb_private::ProcessAttachInfo &
- ref ();
-
- ProcessAttachInfoSP m_opaque_sp;
-};
-
-class SBTarget
+class LLDB_API SBTarget
{
public:
//------------------------------------------------------------------
@@ -187,7 +60,19 @@ public:
bool
IsValid() const;
+
+ static bool
+ EventIsTargetEvent (const lldb::SBEvent &event);
+
+ static lldb::SBTarget
+ GetTargetFromEvent (const lldb::SBEvent &event);
+ static uint32_t
+ GetNumModulesFromEvent (const lldb::SBEvent &event);
+
+ static lldb::SBModule
+ GetModuleAtIndexFromEvent (const uint32_t idx, const lldb::SBEvent &event);
+
static const char *
GetBroadcasterClassName ();
@@ -273,7 +158,7 @@ public:
/// @param[in] stop_at_entry
/// If false do not stop the inferior at the entry point.
///
- /// @param[out]
+ /// @param[out] error
/// An error object. Contains the reason if there is some failure.
///
/// @return
@@ -344,7 +229,7 @@ public:
/// @param[in] pid
/// The process ID to attach to.
///
- /// @param[out]
+ /// @param[out] error
/// An error explaining what went wrong if attach fails.
///
/// @return
@@ -378,7 +263,7 @@ public:
/// @param[in] wait_for
/// If true wait for a new instance of 'name' to be launched.
///
- /// @param[out]
+ /// @param[out] error
/// An error explaining what went wrong if attach fails.
///
/// @return
@@ -405,7 +290,7 @@ public:
/// @param[in] plugin_name
/// The plugin name to be used; can be NULL.
///
- /// @param[out]
+ /// @param[out] error
/// An error explaining what went wrong if the connect fails.
///
/// @return
@@ -764,13 +649,13 @@ public:
lldb::SBBreakpoint
BreakpointCreateBySourceRegex (const char *source_regex,
- const lldb::SBFileSpec &source_file,
+ const SBFileSpec &source_file,
const char *module_name = NULL);
lldb::SBBreakpoint
- BreakpointCreateBySourceRegex (const char *source_regex,
- const SBFileSpecList &module_list,
- const lldb::SBFileSpecList &source_file);
+ BreakpointCreateBySourceRegex (const char *source_regex,
+ const SBFileSpecList &module_list,
+ const SBFileSpecList &source_file);
lldb::SBBreakpoint
BreakpointCreateForException (lldb::LanguageType language,
@@ -888,6 +773,12 @@ public:
lldb::addr_t
GetStackRedZoneSize();
+
+ lldb::SBLaunchInfo
+ GetLaunchInfo () const;
+
+ void
+ SetLaunchInfo (const lldb::SBLaunchInfo &launch_info);
protected:
friend class SBAddress;
diff --git a/include/lldb/API/SBThread.h b/include/lldb/API/SBThread.h
index db15f651f2d5..2c45fa8d5120 100644
--- a/include/lldb/API/SBThread.h
+++ b/include/lldb/API/SBThread.h
@@ -18,7 +18,7 @@ namespace lldb {
class SBFrame;
-class SBThread
+class LLDB_API SBThread
{
public:
enum
diff --git a/include/lldb/API/SBThreadCollection.h b/include/lldb/API/SBThreadCollection.h
index b13cbd938e28..996ee3cd22aa 100644
--- a/include/lldb/API/SBThreadCollection.h
+++ b/include/lldb/API/SBThreadCollection.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBThreadCollection
+class LLDB_API SBThreadCollection
{
public:
diff --git a/include/lldb/API/SBThreadPlan.h b/include/lldb/API/SBThreadPlan.h
index e53942d65fa8..9cc0d0b89bb5 100644
--- a/include/lldb/API/SBThreadPlan.h
+++ b/include/lldb/API/SBThreadPlan.h
@@ -16,7 +16,7 @@
namespace lldb {
-class SBThreadPlan
+class LLDB_API SBThreadPlan
{
friend class lldb_private::ThreadPlan;
diff --git a/include/lldb/API/SBType.h b/include/lldb/API/SBType.h
index 7990fc0696a9..01f0c6afc795 100644
--- a/include/lldb/API/SBType.h
+++ b/include/lldb/API/SBType.h
@@ -16,7 +16,7 @@ namespace lldb {
class SBTypeList;
-class SBTypeMember
+class LLDB_API SBTypeMember
{
public:
SBTypeMember ();
diff --git a/include/lldb/API/SBTypeCategory.h b/include/lldb/API/SBTypeCategory.h
index f123e931e17d..30c338b28a46 100644
--- a/include/lldb/API/SBTypeCategory.h
+++ b/include/lldb/API/SBTypeCategory.h
@@ -14,7 +14,7 @@
namespace lldb {
- class SBTypeCategory
+ class LLDB_API SBTypeCategory
{
public:
diff --git a/include/lldb/API/SBTypeEnumMember.h b/include/lldb/API/SBTypeEnumMember.h
index 75c9917989c2..b141ba0a6bb0 100644
--- a/include/lldb/API/SBTypeEnumMember.h
+++ b/include/lldb/API/SBTypeEnumMember.h
@@ -15,7 +15,7 @@
namespace lldb {
-class SBTypeEnumMember
+class LLDB_API SBTypeEnumMember
{
public:
SBTypeEnumMember ();
diff --git a/include/lldb/API/SBTypeFilter.h b/include/lldb/API/SBTypeFilter.h
index 016954943e28..f030b6a99b60 100644
--- a/include/lldb/API/SBTypeFilter.h
+++ b/include/lldb/API/SBTypeFilter.h
@@ -14,7 +14,7 @@
namespace lldb {
- class SBTypeFilter
+ class LLDB_API SBTypeFilter
{
public:
diff --git a/include/lldb/API/SBTypeFormat.h b/include/lldb/API/SBTypeFormat.h
index eb45ff2b0eba..c24641ac15f5 100644
--- a/include/lldb/API/SBTypeFormat.h
+++ b/include/lldb/API/SBTypeFormat.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBTypeFormat
+class LLDB_API SBTypeFormat
{
public:
diff --git a/include/lldb/API/SBTypeNameSpecifier.h b/include/lldb/API/SBTypeNameSpecifier.h
index 19d1988aa0c5..71700a7123d5 100644
--- a/include/lldb/API/SBTypeNameSpecifier.h
+++ b/include/lldb/API/SBTypeNameSpecifier.h
@@ -14,7 +14,7 @@
namespace lldb {
- class SBTypeNameSpecifier
+ class LLDB_API SBTypeNameSpecifier
{
public:
diff --git a/include/lldb/API/SBTypeSummary.h b/include/lldb/API/SBTypeSummary.h
index 220451e6d70b..9b367ba5f982 100644
--- a/include/lldb/API/SBTypeSummary.h
+++ b/include/lldb/API/SBTypeSummary.h
@@ -15,7 +15,7 @@
#ifndef LLDB_DISABLE_PYTHON
namespace lldb {
- class SBTypeSummaryOptions
+ class LLDB_API SBTypeSummaryOptions
{
public:
SBTypeSummaryOptions();
diff --git a/include/lldb/API/SBTypeSynthetic.h b/include/lldb/API/SBTypeSynthetic.h
index e77cbfef598c..5dd11757ba40 100644
--- a/include/lldb/API/SBTypeSynthetic.h
+++ b/include/lldb/API/SBTypeSynthetic.h
@@ -16,7 +16,7 @@
namespace lldb {
- class SBTypeSynthetic
+ class LLDB_API SBTypeSynthetic
{
public:
diff --git a/include/lldb/API/SBUnixSignals.h b/include/lldb/API/SBUnixSignals.h
index 40bbed8b48ef..9eae30739bb8 100644
--- a/include/lldb/API/SBUnixSignals.h
+++ b/include/lldb/API/SBUnixSignals.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBUnixSignals {
+class LLDB_API SBUnixSignals {
public:
SBUnixSignals ();
diff --git a/include/lldb/API/SBValue.h b/include/lldb/API/SBValue.h
index bedac4ef1d2d..a070b149f34f 100644
--- a/include/lldb/API/SBValue.h
+++ b/include/lldb/API/SBValue.h
@@ -19,10 +19,8 @@ class ValueLocker;
namespace lldb {
-class SBValue
+class LLDB_API SBValue
{
-friend class ValueLocker;
-
public:
SBValue ();
@@ -84,6 +82,7 @@ public:
ValueType
GetValueType ();
+ // If you call this on a newly created ValueObject, it will always return false.
bool
GetValueDidChange ();
@@ -223,7 +222,7 @@ public:
/// and also if the target can be run to figure out the dynamic
/// type of the child value.
///
- /// @param[in] synthetic_allowed
+ /// @param[in] can_create_synthetic
/// If \b true, then allow child values to be created by index
/// for pointers and arrays for indexes that normally wouldn't
/// be allowed.
@@ -326,6 +325,9 @@ public:
//------------------------------------------------------------------
bool
MightHaveChildren ();
+
+ bool
+ IsRuntimeSupportValue ();
uint32_t
GetNumChildren ();
@@ -386,7 +388,7 @@ public:
/// @param[in] write
/// Stop when this value is modified
///
- /// @param[out]
+ /// @param[out] error
/// An error object. Contains the reason if there is some failure.
///
/// @return
@@ -419,7 +421,7 @@ public:
/// @param[in] write
/// Stop when this value is modified
///
- /// @param[out]
+ /// @param[out] error
/// An error object. Contains the reason if there is some failure.
///
/// @return
diff --git a/include/lldb/API/SBValueList.h b/include/lldb/API/SBValueList.h
index 812fdac91c11..563ca3d7e1bf 100644
--- a/include/lldb/API/SBValueList.h
+++ b/include/lldb/API/SBValueList.h
@@ -16,7 +16,7 @@ class ValueListImpl;
namespace lldb {
-class SBValueList
+class LLDB_API SBValueList
{
public:
diff --git a/include/lldb/API/SBVariablesOptions.h b/include/lldb/API/SBVariablesOptions.h
new file mode 100644
index 000000000000..527310f5dfc7
--- /dev/null
+++ b/include/lldb/API/SBVariablesOptions.h
@@ -0,0 +1,98 @@
+//===-- SBVariablesOptions.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_SBVariablesOptions_h_
+#define LLDB_SBVariablesOptions_h_
+
+#include "lldb/API/SBDefines.h"
+
+class VariablesOptionsImpl;
+
+namespace lldb {
+
+class LLDB_API SBVariablesOptions
+{
+public:
+ SBVariablesOptions ();
+
+ SBVariablesOptions (const SBVariablesOptions& options);
+
+ SBVariablesOptions&
+ operator = (const SBVariablesOptions& options);
+
+ ~SBVariablesOptions ();
+
+ bool
+ IsValid () const;
+
+ bool
+ GetIncludeArguments () const;
+
+ void
+ SetIncludeArguments (bool);
+
+ bool
+ GetIncludeLocals () const;
+
+ void
+ SetIncludeLocals (bool);
+
+ bool
+ GetIncludeStatics () const;
+
+ void
+ SetIncludeStatics (bool);
+
+ bool
+ GetInScopeOnly () const;
+
+ void
+ SetInScopeOnly (bool);
+
+ bool
+ GetIncludeRuntimeSupportValues () const;
+
+ void
+ SetIncludeRuntimeSupportValues (bool);
+
+ lldb::DynamicValueType
+ GetUseDynamic () const;
+
+ void
+ SetUseDynamic (lldb::DynamicValueType);
+
+protected:
+ VariablesOptionsImpl *
+ operator->();
+
+ const VariablesOptionsImpl *
+ operator->() const;
+
+ VariablesOptionsImpl *
+ get ();
+
+ VariablesOptionsImpl &
+ ref();
+
+ const VariablesOptionsImpl &
+ ref() const;
+
+ SBVariablesOptions (VariablesOptionsImpl *lldb_object_ptr);
+
+ void
+ SetOptions (VariablesOptionsImpl *lldb_object_ptr);
+
+private:
+
+ std::unique_ptr<VariablesOptionsImpl> m_opaque_ap;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBValue_h_
diff --git a/include/lldb/API/SBWatchpoint.h b/include/lldb/API/SBWatchpoint.h
index 9bf51fd1ad05..5d0d48ee12f2 100644
--- a/include/lldb/API/SBWatchpoint.h
+++ b/include/lldb/API/SBWatchpoint.h
@@ -14,7 +14,7 @@
namespace lldb {
-class SBWatchpoint
+class LLDB_API SBWatchpoint
{
public:
diff --git a/include/lldb/API/SystemInitializerFull.h b/include/lldb/API/SystemInitializerFull.h
new file mode 100644
index 000000000000..6280fe8aef04
--- /dev/null
+++ b/include/lldb/API/SystemInitializerFull.h
@@ -0,0 +1,40 @@
+//===-- SystemInitializerFull.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_API_SYSTEM_INITIALIZER_FULL_H
+#define LLDB_API_SYSTEM_INITIALIZER_FULL_H
+
+#include "lldb/Initialization/SystemInitializerCommon.h"
+
+namespace lldb_private
+{
+//------------------------------------------------------------------
+/// Initializes lldb.
+///
+/// This class is responsible for initializing all of lldb system
+/// services needed to use the full LLDB application. This class is
+/// not intended to be used externally, but is instead used
+/// internally by SBDebugger to initialize the system.
+//------------------------------------------------------------------
+class SystemInitializerFull : public SystemInitializerCommon
+{
+ public:
+ SystemInitializerFull();
+ virtual ~SystemInitializerFull();
+
+ void Initialize() override;
+ void Terminate() override;
+
+ private:
+ void InitializeSWIG();
+ void TerminateSWIG();
+};
+}
+
+#endif
diff --git a/include/lldb/Breakpoint/Breakpoint.h b/include/lldb/Breakpoint/Breakpoint.h
index 883571a3ce9a..a70c2787a1ef 100644
--- a/include/lldb/Breakpoint/Breakpoint.h
+++ b/include/lldb/Breakpoint/Breakpoint.h
@@ -155,6 +155,23 @@ public:
};
+ class BreakpointPrecondition
+ {
+ public:
+ virtual ~BreakpointPrecondition() {}
+
+ virtual bool
+ EvaluatePrecondition(StoppointCallbackContext &context);
+
+ virtual Error
+ ConfigurePrecondition(Args &options);
+
+ virtual void
+ DescribePrecondition(Stream &stream, lldb::DescriptionLevel level);
+ };
+
+ typedef std::shared_ptr<BreakpointPrecondition> BreakpointPreconditionSP;
+
//------------------------------------------------------------------
/// Destructor.
///
@@ -665,6 +682,31 @@ public:
}
}
+ //------------------------------------------------------------------
+ /// Set a pre-condition filter that overrides all user provided filters/callbacks etc.
+ ///
+ /// Used to define fancy breakpoints that can do dynamic hit detection without taking up the condition slot -
+ /// which really belongs to the user anyway...
+ ///
+ /// The Precondition should not continue the target, it should return true if the condition says to stop and
+ /// false otherwise.
+ ///
+ //------------------------------------------------------------------
+ void
+ SetPrecondition(BreakpointPreconditionSP precondition_sp)
+ {
+ m_precondition_sp = precondition_sp;
+ }
+
+ bool
+ EvaluatePrecondition (StoppointCallbackContext &context);
+
+ BreakpointPreconditionSP
+ GetPrecondition()
+ {
+ return m_precondition_sp;
+ }
+
protected:
friend class Target;
//------------------------------------------------------------------
@@ -737,13 +779,17 @@ private:
// For Breakpoint only
//------------------------------------------------------------------
bool m_being_created;
- bool m_hardware; // If this breakpoint is required to use a hardware breakpoint
- Target &m_target; // The target that holds this breakpoint.
+ bool m_hardware; // If this breakpoint is required to use a hardware breakpoint
+ Target &m_target; // The target that holds this breakpoint.
std::unordered_set<std::string> m_name_list; // If not empty, this is the name of this breakpoint (many breakpoints can share the same name.)
- lldb::SearchFilterSP m_filter_sp; // The filter that constrains the breakpoint's domain.
- lldb::BreakpointResolverSP m_resolver_sp; // The resolver that defines this breakpoint.
- BreakpointOptions m_options; // Settable breakpoint options
- BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint.
+ lldb::SearchFilterSP m_filter_sp; // The filter that constrains the breakpoint's domain.
+ lldb::BreakpointResolverSP m_resolver_sp; // The resolver that defines this breakpoint.
+ BreakpointPreconditionSP m_precondition_sp; // The precondition is a breakpoint-level hit filter that can be used
+ // to skip certain breakpoint hits. For instance, exception breakpoints
+ // use this to limit the stop to certain exception classes, while leaving
+ // the condition & callback free for user specification.
+ BreakpointOptions m_options; // Settable breakpoint options
+ BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint.
std::string m_kind_description;
bool m_resolve_indirect_symbols;
uint32_t m_hit_count; // Number of times this breakpoint/watchpoint has been hit. This is kept
diff --git a/include/lldb/Breakpoint/BreakpointLocation.h b/include/lldb/Breakpoint/BreakpointLocation.h
index 642256386785..c3e620d085c6 100644
--- a/include/lldb/Breakpoint/BreakpointLocation.h
+++ b/include/lldb/Breakpoint/BreakpointLocation.h
@@ -21,11 +21,8 @@
#include "lldb/lldb-private.h"
#include "lldb/Breakpoint/StoppointLocation.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Core/UserID.h"
#include "lldb/Host/Mutex.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Expression/ClangUserExpression.h"
namespace lldb_private {
@@ -464,7 +461,7 @@ private:
Breakpoint &m_owner; ///< The breakpoint that produced this object.
std::unique_ptr<BreakpointOptions> m_options_ap; ///< Breakpoint options pointer, NULL if we're using our breakpoint's options.
lldb::BreakpointSiteSP m_bp_site_sp; ///< Our breakpoint site (it may be shared by more than one location.)
- ClangUserExpression::ClangUserExpressionSP m_user_expression_sp; ///< The compiled expression to use in testing our condition.
+ lldb::ClangUserExpressionSP m_user_expression_sp; ///< The compiled expression to use in testing our condition.
Mutex m_condition_mutex; ///< Guards parsing and evaluation of the condition, which could be evaluated by multiple processes.
size_t m_condition_hash; ///< For testing whether the condition source code changed.
diff --git a/include/lldb/Breakpoint/BreakpointOptions.h b/include/lldb/Breakpoint/BreakpointOptions.h
index eb374ad69603..bf10fc096d75 100644
--- a/include/lldb/Breakpoint/BreakpointOptions.h
+++ b/include/lldb/Breakpoint/BreakpointOptions.h
@@ -89,6 +89,9 @@ public:
// callback.
// Asynchronous callbacks get run as part of the "ShouldStop" logic in the thread plan. The logic there is:
// a) If the breakpoint is thread specific and not for this thread, continue w/o running the callback.
+ // NB. This is actually enforced underneath the breakpoint system, the Process plugin is expected to
+ // call BreakpointSite::IsValidForThread, and set the thread's StopInfo to "no reason". That way,
+ // thread displays won't show stops for breakpoints not for that thread...
// b) If the ignore count says we shouldn't stop, then ditto.
// c) If the condition says we shouldn't stop, then ditto.
// d) Otherwise, the callback will get run, and if it returns true we will stop, and if false we won't.
diff --git a/include/lldb/Breakpoint/BreakpointResolverFileLine.h b/include/lldb/Breakpoint/BreakpointResolverFileLine.h
index cd62bcd032b0..2403d24515a7 100644
--- a/include/lldb/Breakpoint/BreakpointResolverFileLine.h
+++ b/include/lldb/Breakpoint/BreakpointResolverFileLine.h
@@ -32,7 +32,8 @@ public:
const FileSpec &resolver,
uint32_t line_no,
bool check_inlines,
- bool skip_prologue);
+ bool skip_prologue,
+ bool exact_match);
virtual
~BreakpointResolverFileLine ();
@@ -67,6 +68,7 @@ protected:
uint32_t m_line_number; // This is the line number that we are looking for.
bool m_inlines; // This determines whether the resolver looks for inlined functions or not.
bool m_skip_prologue;
+ bool m_exact_match;
private:
DISALLOW_COPY_AND_ASSIGN(BreakpointResolverFileLine);
diff --git a/include/lldb/Breakpoint/BreakpointResolverFileRegex.h b/include/lldb/Breakpoint/BreakpointResolverFileRegex.h
index 2c05ac1c87da..8e18fff16447 100644
--- a/include/lldb/Breakpoint/BreakpointResolverFileRegex.h
+++ b/include/lldb/Breakpoint/BreakpointResolverFileRegex.h
@@ -29,7 +29,8 @@ class BreakpointResolverFileRegex :
{
public:
BreakpointResolverFileRegex (Breakpoint *bkpt,
- RegularExpression &regex);
+ RegularExpression &regex,
+ bool exact_match);
virtual
~BreakpointResolverFileRegex ();
@@ -61,6 +62,7 @@ public:
protected:
friend class Breakpoint;
RegularExpression m_regex; // This is the line expression that we are looking for.
+ bool m_exact_match;
private:
DISALLOW_COPY_AND_ASSIGN(BreakpointResolverFileRegex);
diff --git a/include/lldb/Breakpoint/BreakpointSite.h b/include/lldb/Breakpoint/BreakpointSite.h
index c6dbef781f22..d67fc8bb57f1 100644
--- a/include/lldb/Breakpoint/BreakpointSite.h
+++ b/include/lldb/Breakpoint/BreakpointSite.h
@@ -18,7 +18,7 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-forward.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Core/UserID.h"
#include "lldb/Breakpoint/StoppointLocation.h"
diff --git a/include/lldb/Breakpoint/Watchpoint.h b/include/lldb/Breakpoint/Watchpoint.h
index 8493775eec34..926e0b506f31 100644
--- a/include/lldb/Breakpoint/Watchpoint.h
+++ b/include/lldb/Breakpoint/Watchpoint.h
@@ -20,10 +20,11 @@
// Project includes
#include "lldb/lldb-private.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Breakpoint/WatchpointOptions.h"
#include "lldb/Breakpoint/StoppointLocation.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Target/Target.h"
namespace lldb_private {
@@ -205,7 +206,18 @@ private:
friend class Target;
friend class WatchpointList;
- void ResetHitCount() { m_hit_count = 0; }
+ void
+ ResetHitCount ()
+ {
+ m_hit_count = 0;
+ }
+
+ void
+ ResetHistoricValues ()
+ {
+ m_old_value_sp.reset(nullptr);
+ m_new_value_sp.reset(nullptr);
+ }
Target &m_target;
bool m_enabled; // Is this watchpoint enabled
diff --git a/include/lldb/Core/Address.h b/include/lldb/Core/Address.h
index b430ef7cec21..cfa16c30bedb 100644
--- a/include/lldb/Core/Address.h
+++ b/include/lldb/Core/Address.h
@@ -88,6 +88,8 @@ public:
///< if the address is in a section (section of pointers, c strings, etc).
DumpStyleResolvedDescriptionNoModule,
DumpStyleResolvedDescriptionNoFunctionArguments,
+ DumpStyleNoFunctionName, ///< Elide the function name; display an offset into the current function.
+ ///< Used primarily in disassembly symbolication
DumpStyleDetailedSymbolContext, ///< Detailed symbol context information for an address for all symbol
///< context members.
DumpStyleResolvedPointerDescription ///< Dereference a pointer at the current address and then lookup the
diff --git a/include/lldb/Core/ArchSpec.h b/include/lldb/Core/ArchSpec.h
index 93630f043822..0cadd8d8dec6 100644
--- a/include/lldb/Core/ArchSpec.h
+++ b/include/lldb/Core/ArchSpec.h
@@ -12,9 +12,8 @@
#if defined(__cplusplus)
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-forward.h"
#include "lldb/Core/ConstString.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
namespace lldb_private {
@@ -33,6 +32,23 @@ struct CoreDefinition;
class ArchSpec
{
public:
+ enum MIPSSubType
+ {
+ eMIPSSubType_unknown,
+ eMIPSSubType_mips32,
+ eMIPSSubType_mips32r2,
+ eMIPSSubType_mips32r6,
+ eMIPSSubType_mips32el,
+ eMIPSSubType_mips32r2el,
+ eMIPSSubType_mips32r6el,
+ eMIPSSubType_mips64,
+ eMIPSSubType_mips64r2,
+ eMIPSSubType_mips64r6,
+ eMIPSSubType_mips64el,
+ eMIPSSubType_mips64r2el,
+ eMIPSSubType_mips64r6el,
+ };
+
enum Core
{
eCore_arm_generic,
@@ -66,8 +82,27 @@ public:
eCore_arm_arm64,
eCore_arm_armv8,
eCore_arm_aarch64,
-
+
+ eCore_mips32,
+ eCore_mips32r2,
+ eCore_mips32r3,
+ eCore_mips32r5,
+ eCore_mips32r6,
+ eCore_mips32el,
+ eCore_mips32r2el,
+ eCore_mips32r3el,
+ eCore_mips32r5el,
+ eCore_mips32r6el,
eCore_mips64,
+ eCore_mips64r2,
+ eCore_mips64r3,
+ eCore_mips64r5,
+ eCore_mips64r6,
+ eCore_mips64el,
+ eCore_mips64r2el,
+ eCore_mips64r3el,
+ eCore_mips64r5el,
+ eCore_mips64r6el,
eCore_ppc_generic,
eCore_ppc_ppc601,
@@ -142,7 +177,19 @@ public:
kCore_hexagon_last = eCore_hexagon_hexagonv5,
kCore_kalimba_first = eCore_kalimba3,
- kCore_kalimba_last = eCore_kalimba5
+ kCore_kalimba_last = eCore_kalimba5,
+
+ kCore_mips32_first = eCore_mips32,
+ kCore_mips32_last = eCore_mips32r6,
+
+ kCore_mips32el_first = eCore_mips32el,
+ kCore_mips32el_last = eCore_mips32r6el,
+
+ kCore_mips64_first = eCore_mips64,
+ kCore_mips64_last = eCore_mips64r6,
+
+ kCore_mips64el_first = eCore_mips64el,
+ kCore_mips64el_last = eCore_mips64r6el
};
typedef void (* StopInfoOverrideCallbackType)(lldb_private::Thread &thread);
@@ -290,58 +337,48 @@ public:
//------------------------------------------------------------------
void
MergeFrom(const ArchSpec &other);
-
- //------------------------------------------------------------------
- /// Sets this ArchSpec according to the given architecture name.
- ///
- /// The architecture name can be one of the generic system default
- /// values:
- ///
- /// @li \c LLDB_ARCH_DEFAULT - The arch the current system defaults
- /// to when a program is launched without any extra
- /// attributes or settings.
- /// @li \c LLDB_ARCH_DEFAULT_32BIT - The default host architecture
- /// for 32 bit (if any).
- /// @li \c LLDB_ARCH_DEFAULT_64BIT - The default host architecture
- /// for 64 bit (if any).
- ///
- /// Alternatively, if the object type of this ArchSpec has been
- /// configured, a concrete architecture can be specified to set
- /// the CPU type ("x86_64" for example).
- ///
- /// Finally, an encoded object and archetecture format is accepted.
- /// The format contains an object type (like "macho" or "elf"),
- /// followed by a platform dependent encoding of CPU type and
- /// subtype. For example:
- ///
- /// "macho" : Specifies an object type of MachO.
- /// "macho-16-6" : MachO specific encoding for ARMv6.
- /// "elf-43 : ELF specific encoding for Sparc V9.
- ///
- /// @param[in] arch_name The name of an architecture.
- ///
- /// @return True if @p arch_name was successfully translated, false
- /// otherwise.
- //------------------------------------------------------------------
-// bool
-// SetArchitecture (const llvm::StringRef& arch_name);
-//
-// bool
-// SetArchitecture (const char *arch_name);
//------------------------------------------------------------------
- /// Change the architecture object type and CPU type.
+ /// Change the architecture object type, CPU type and OS type.
///
/// @param[in] arch_type The object type of this ArchSpec.
///
/// @param[in] cpu The required CPU type.
///
- /// @return True if the object and CPU type were successfully set.
+ /// @param[in] os The optional OS type
+ /// The default value of 0 was choosen to from the ELF spec value
+ /// ELFOSABI_NONE. ELF is the only one using this parameter. If another
+ /// format uses this parameter and 0 does not work, use a value over
+ /// 255 because in the ELF header this is value is only a byte.
+ ///
+ /// @return True if the object, and CPU were successfully set.
+ ///
+ /// As a side effect, the vendor value is usually set to unknown.
+ /// The exections are
+ /// aarch64-apple-ios
+ /// arm-apple-ios
+ /// thumb-apple-ios
+ /// x86-apple-
+ /// x86_64-apple-
+ ///
+ /// As a side effect, the os value is usually set to unknown
+ /// The exceptions are
+ /// *-*-aix
+ /// aarch64-apple-ios
+ /// arm-apple-ios
+ /// thumb-apple-ios
+ /// powerpc-apple-darwin
+ /// *-*-freebsd
+ /// *-*-linux
+ /// *-*-netbsd
+ /// *-*-openbsd
+ /// *-*-solaris
//------------------------------------------------------------------
bool
SetArchitecture (ArchitectureType arch_type,
uint32_t cpu,
- uint32_t sub);
+ uint32_t sub,
+ uint32_t os = 0);
//------------------------------------------------------------------
/// Returns the byte order for the architecture specification.
@@ -456,8 +493,18 @@ public:
GetDefaultEndian () const;
//------------------------------------------------------------------
- /// Compare an ArchSpec to another ArchSpec, requiring an exact cpu
- /// type match between them.
+ /// Returns true if 'char' is a signed type by defualt in the
+ /// architecture false otherwise
+ ///
+ /// @return True if 'char' is a signed type by default on the
+ /// architecture and false otherwise.
+ //------------------------------------------------------------------
+ bool
+ CharIsSignedByDefault () const;
+
+ //------------------------------------------------------------------
+ /// Compare an ArchSpec to another ArchSpec, requiring an exact cpu
+ /// type match between them.
/// e.g. armv7s is not an exact match with armv7 - this would return false
///
/// @return true if the two ArchSpecs match.
diff --git a/include/lldb/Core/ClangForward.h b/include/lldb/Core/ClangForward.h
index ef7308d25f7f..6c627c2ad3b7 100644
--- a/include/lldb/Core/ClangForward.h
+++ b/include/lldb/Core/ClangForward.h
@@ -72,11 +72,14 @@ namespace clang
class FunctionTemplateSpecializationInfo;
class GotoStmt;
class HeaderSearchOptions;
+ class IdentifierInfo;
class IdentifierTable;
class IntegerLiteral;
class LabelStmt;
class LangOptions;
+ class MacroDirective;
class MemberExpr;
+ class Module;
class NamedDecl;
class NamespaceDecl;
class NonTypeTemplateParmDecl;
diff --git a/include/lldb/Core/Communication.h b/include/lldb/Core/Communication.h
index 49532fe123c5..7924ed293d3c 100644
--- a/include/lldb/Core/Communication.h
+++ b/include/lldb/Core/Communication.h
@@ -85,14 +85,16 @@ namespace lldb_private {
class Communication : public Broadcaster
{
public:
- enum {
- eBroadcastBitDisconnected = (1 << 0), ///< Sent when the communications connection is lost.
- eBroadcastBitReadThreadGotBytes = (1 << 1), ///< Sent by the read thread when bytes become available.
- eBroadcastBitReadThreadDidExit = (1 << 2), ///< Sent by the read thread when it exits to inform clients.
- eBroadcastBitReadThreadShouldExit = (1 << 3), ///< Sent by clients that need to cancel the read thread.
- eBroadcastBitPacketAvailable = (1 << 4), ///< Sent when data received makes a complete packet.
- kLoUserBroadcastBit = (1 << 16),///< Subclasses can used bits 31:16 for any needed events.
- kHiUserBroadcastBit = (1 << 31),
+ FLAGS_ANONYMOUS_ENUM()
+ {
+ eBroadcastBitDisconnected = (1u << 0), ///< Sent when the communications connection is lost.
+ eBroadcastBitReadThreadGotBytes = (1u << 1), ///< Sent by the read thread when bytes become available.
+ eBroadcastBitReadThreadDidExit = (1u << 2), ///< Sent by the read thread when it exits to inform clients.
+ eBroadcastBitReadThreadShouldExit = (1u << 3), ///< Sent by clients that need to cancel the read thread.
+ eBroadcastBitPacketAvailable = (1u << 4), ///< Sent when data received makes a complete packet.
+ eBroadcastBitNoMorePendingInput = (1u << 5), ///< Sent by the read thread to indicate all pending input has been processed.
+ kLoUserBroadcastBit = (1u << 16),///< Subclasses can used bits 31:16 for any needed events.
+ kHiUserBroadcastBit = (1u << 31),
eAllEventBits = 0xffffffff
};
@@ -321,6 +323,16 @@ public:
SetReadThreadBytesReceivedCallback (ReadThreadBytesReceived callback,
void *callback_baton);
+
+ //------------------------------------------------------------------
+ /// Wait for the read thread to process all outstanding data.
+ ///
+ /// After this function returns, the read thread has processed all data that
+ /// has been waiting in the Connection queue.
+ ///
+ //------------------------------------------------------------------
+ void SynchronizeWithReadThread ();
+
static const char *
ConnectionStatusAsCString (lldb::ConnectionStatus status);
@@ -354,9 +366,11 @@ protected:
lldb::ConnectionSP m_connection_sp; ///< The connection that is current in use by this communications class.
HostThread m_read_thread; ///< The read thread handle in case we need to cancel the thread.
std::atomic<bool> m_read_thread_enabled;
+ std::atomic<bool> m_read_thread_did_exit;
std::string m_bytes; ///< A buffer to cache bytes read in the ReadThread function.
Mutex m_bytes_mutex; ///< A mutex to protect multi-threaded access to the cached bytes.
Mutex m_write_mutex; ///< Don't let multiple threads write at the same time...
+ Mutex m_synchronize_mutex;
ReadThreadBytesReceived m_callback;
void *m_callback_baton;
bool m_close_on_eof;
diff --git a/include/lldb/Core/Connection.h b/include/lldb/Core/Connection.h
index a7b911ac382f..c354519a222e 100644
--- a/include/lldb/Core/Connection.h
+++ b/include/lldb/Core/Connection.h
@@ -111,6 +111,13 @@ public:
/// The number of bytes to attempt to read, and also the max
/// number of bytes that can be placed into \a dst.
///
+ /// @param[in] timeout_usec
+ /// The number of microseconds to wait for the data.
+ ///
+ /// @param[out] status
+ /// On return, indicates whether the call was sucessful or terminated
+ /// due to some error condition.
+ ///
/// @param[out] error_ptr
/// A pointer to an error object that should be given an
/// approriate error value if this method returns zero. This
@@ -164,6 +171,22 @@ public:
virtual std::string
GetURI() = 0;
+ //------------------------------------------------------------------
+ /// Interrupts an ongoing Read() operation.
+ ///
+ /// If there is an ongoing read operation in another thread, this operation
+ /// return with status == eConnectionStatusInterrupted. Note that if there
+ /// data waiting to be read and an interrupt request is issued, the Read()
+ /// function will return the data immediately without processing the
+ /// interrupt request (which will remain queued for the next Read()
+ /// operation).
+ ///
+ /// @return
+ /// Returns true is the interrupt request was sucessful.
+ //------------------------------------------------------------------
+ virtual bool
+ InterruptRead() = 0;
+
private:
//------------------------------------------------------------------
// For Connection only
diff --git a/include/lldb/Core/ConstString.h b/include/lldb/Core/ConstString.h
index cfa237c46862..cfe8ea2db0e1 100644
--- a/include/lldb/Core/ConstString.h
+++ b/include/lldb/Core/ConstString.h
@@ -233,7 +233,7 @@ public:
const char *
AsCString(const char *value_if_empty = NULL) const
{
- if (m_string == NULL)
+ if (IsEmpty())
return value_if_empty;
return m_string;
}
diff --git a/include/lldb/Core/CxaDemangle.h b/include/lldb/Core/CxaDemangle.h
new file mode 100644
index 000000000000..0cd54fb36a32
--- /dev/null
+++ b/include/lldb/Core/CxaDemangle.h
@@ -0,0 +1,21 @@
+//===-- CxaDemangle.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_CxaDemangle_h_
+#define liblldb_CxaDemangle_h_
+
+namespace lldb_private
+{
+
+ char*
+ __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status);
+
+}
+
+#endif
diff --git a/include/lldb/Core/DataEncoder.h b/include/lldb/Core/DataEncoder.h
index 7cd5d6808152..7889f4191e50 100644
--- a/include/lldb/Core/DataEncoder.h
+++ b/include/lldb/Core/DataEncoder.h
@@ -357,7 +357,7 @@ public:
/// The number of bytes that this object now contains.
//------------------------------------------------------------------
uint32_t
- SetData (const void *bytes, uint32_t length, lldb::ByteOrder byte_order);
+ SetData (void *bytes, uint32_t length, lldb::ByteOrder byte_order);
//------------------------------------------------------------------
/// Adopt a subset of shared data in \a data_sp.
@@ -446,7 +446,7 @@ protected:
uint8_t *m_end; ///< A pointer to the byte that is past the end of the data.
lldb::ByteOrder m_byte_order; ///< The byte order of the data we are extracting from.
uint8_t m_addr_size; ///< The address size to use when extracting pointers or addresses
- mutable lldb::DataBufferSP m_data_sp; ///< The shared pointer to data that can be shared among multilple instances
+ mutable lldb::DataBufferSP m_data_sp; ///< The shared pointer to data that can be shared among multiple instances
private:
DISALLOW_COPY_AND_ASSIGN (DataEncoder);
diff --git a/include/lldb/Core/DataExtractor.h b/include/lldb/Core/DataExtractor.h
index 516953b00c33..e61189b98103 100644
--- a/include/lldb/Core/DataExtractor.h
+++ b/include/lldb/Core/DataExtractor.h
@@ -234,7 +234,7 @@ public:
/// bytes into the contained data, into the stream \a s. \a
/// num_per_line objects will be dumped on each line before a new
/// line will be output. If \a base_addr is a valid address, then
- /// each new line of output will be prededed by the address value
+ /// each new line of output will be preceded by the address value
/// plus appropriate offset, and a colon and space. Bitfield values
/// can be dumped by calling this function multiple times with the
/// same start offset, format and size, yet differing \a
@@ -574,7 +574,7 @@ public:
GetSharedDataOffset () const;
//------------------------------------------------------------------
- /// Get a the data start pointer.
+ /// Get the data start pointer.
///
/// @return
/// Returns a pointer to the first byte contained in this
@@ -908,7 +908,7 @@ public:
///
/// @return
/// \a dst if all values were properly extracted and copied,
- /// NULL otherise.
+ /// NULL otherwise.
//------------------------------------------------------------------
void *
GetU8 (lldb::offset_t *offset_ptr, void *dst, uint32_t count) const;
@@ -955,7 +955,7 @@ public:
///
/// @return
/// \a dst if all values were properly extracted and copied,
- /// NULL otherise.
+ /// NULL otherwise.
//------------------------------------------------------------------
void *
GetU16 (lldb::offset_t *offset_ptr, void *dst, uint32_t count) const;
@@ -1002,7 +1002,7 @@ public:
///
/// @return
/// \a dst if all values were properly extracted and copied,
- /// NULL otherise.
+ /// NULL otherwise.
//------------------------------------------------------------------
void *
GetU32 (lldb::offset_t *offset_ptr, void *dst, uint32_t count) const;
@@ -1049,7 +1049,7 @@ public:
///
/// @return
/// \a dst if all values were properly extracted and copied,
- /// NULL otherise.
+ /// NULL otherwise.
//------------------------------------------------------------------
void *
GetU64 ( lldb::offset_t *offset_ptr, void *dst, uint32_t count) const;
@@ -1328,7 +1328,7 @@ protected:
const uint8_t * m_end; ///< A pointer to the byte that is past the end of the data.
lldb::ByteOrder m_byte_order; ///< The byte order of the data we are extracting from.
uint32_t m_addr_size; ///< The address size to use when extracting pointers or addresses
- mutable lldb::DataBufferSP m_data_sp; ///< The shared pointer to data that can be shared among multilple instances
+ mutable lldb::DataBufferSP m_data_sp; ///< The shared pointer to data that can be shared among multiple instances
const uint32_t m_target_byte_size;
};
diff --git a/include/lldb/Core/Debugger.h b/include/lldb/Core/Debugger.h
index 9a3f9736fdca..0d9b90c8919d 100644
--- a/include/lldb/Core/Debugger.h
+++ b/include/lldb/Core/Debugger.h
@@ -14,22 +14,16 @@
#include <stdint.h>
-#include <stack>
-
#include "lldb/lldb-public.h"
#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/Communication.h"
#include "lldb/Core/FormatEntity.h"
#include "lldb/Core/IOHandler.h"
#include "lldb/Core/Listener.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Core/UserID.h"
#include "lldb/Core/UserSettingsController.h"
-#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/Terminal.h"
-#include "lldb/Interpreter/OptionValueProperties.h"
-#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/TargetList.h"
@@ -61,10 +55,6 @@ friend class SourceManager; // For GetSourceFileCache.
public:
- 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);
@@ -75,10 +65,10 @@ public:
FindTargetWithProcess (Process *process);
static void
- Initialize (LoadPluginCallbackType load_plugin_callback);
+ Initialize(LoadPluginCallbackType load_plugin_callback);
- static void
- Terminate ();
+ static void
+ Terminate();
static void
SettingsInitialize ();
@@ -220,6 +210,9 @@ public:
bool
IsTopIOHandler (const lldb::IOHandlerSP& reader_sp);
+ void
+ PrintAsync (const char *s, size_t len, bool is_stdout);
+
ConstString
GetTopIOHandlerControlSequence(char ch);
@@ -229,12 +222,6 @@ public:
const char *
GetIOHandlerHelpPrologue();
- bool
- HideTopIOHandler();
-
- void
- RefreshTopIOHandler();
-
static lldb::DebuggerSP
FindDebuggerWithID (lldb::user_id_t id);
@@ -258,9 +245,6 @@ public:
void
ClearIOHandlers ();
- static int
- TestDebuggerRefCount ();
-
bool
GetCloseInputOnEOF () const;
@@ -360,7 +344,7 @@ public:
LoadPlugin (const FileSpec& spec, Error& error);
void
- ExecuteIOHanders();
+ ExecuteIOHandlers();
bool
IsForwardingEvents ();
diff --git a/include/lldb/Core/Disassembler.h b/include/lldb/Core/Disassembler.h
index 64d35e67bfd0..e08e2def4c18 100644
--- a/include/lldb/Core/Disassembler.h
+++ b/include/lldb/Core/Disassembler.h
@@ -120,6 +120,12 @@ public:
/// @param[in] disassembly_addr_format
/// The format specification for how addresses are printed.
/// Only needed if show_address is true.
+ ///
+ /// @param[in] max_address_text_size
+ /// The length of the longest address string at the start of the
+ /// disassembly line that will be printed (the Debugger::FormatDisassemblerAddress() string)
+ /// so this method can properly align the instruction opcodes.
+ /// May be 0 to indicate no indentation/alignment of the opcodes.
//------------------------------------------------------------------
virtual void
@@ -130,7 +136,8 @@ public:
const ExecutionContext* exe_ctx,
const SymbolContext *sym_ctx,
const SymbolContext *prev_sym_ctx,
- const FormatEntity::Entry *disassembly_addr_format);
+ const FormatEntity::Entry *disassembly_addr_format,
+ size_t max_address_text_size);
virtual bool
DoesBranch () = 0;
@@ -218,7 +225,7 @@ public:
GetInstructionAtIndex (size_t idx) const;
uint32_t
- GetIndexOfNextBranchInstruction(uint32_t start) const;
+ GetIndexOfNextBranchInstruction(uint32_t start, Target &target) const;
uint32_t
GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target);
diff --git a/include/lldb/Core/FastDemangle.h b/include/lldb/Core/FastDemangle.h
new file mode 100644
index 000000000000..cd6128c73038
--- /dev/null
+++ b/include/lldb/Core/FastDemangle.h
@@ -0,0 +1,24 @@
+//===-- FastDemangle.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_FastDemangle_h_
+#define liblldb_FastDemangle_h_
+
+namespace lldb_private
+{
+
+ char *
+ FastDemangle(const char *mangled_name);
+
+ char *
+ FastDemangle(const char *mangled_name, long mangled_name_length);
+
+}
+
+#endif
diff --git a/include/lldb/Core/FormatEntity.h b/include/lldb/Core/FormatEntity.h
index 32ff9ea4e3eb..db4f59132832 100644
--- a/include/lldb/Core/FormatEntity.h
+++ b/include/lldb/Core/FormatEntity.h
@@ -61,6 +61,7 @@ namespace lldb_private
ScriptTarget,
ModuleFile,
File,
+ Lang,
FrameIndex,
FrameRegisterPC,
FrameRegisterSP,
@@ -78,6 +79,8 @@ namespace lldb_private
FunctionAddrOffsetConcrete,
FunctionLineOffset,
FunctionPCOffset,
+ FunctionInitial,
+ FunctionChanged,
LineEntryFile,
LineEntryLineNumber,
LineEntryStartAddress,
diff --git a/include/lldb/Core/IOHandler.h b/include/lldb/Core/IOHandler.h
index 02e6bde1edb6..b617d8e75f58 100644
--- a/include/lldb/Core/IOHandler.h
+++ b/include/lldb/Core/IOHandler.h
@@ -67,18 +67,6 @@ namespace lldb_private {
virtual void
Run () = 0;
- // Hide any characters that have been displayed so far so async
- // output can be displayed. Refresh() will be called after the
- // output has been displayed.
- virtual void
- Hide () = 0;
-
- // Called when the async output has been received in order to update
- // the input reader (refresh the prompt and redisplay any current
- // line(s) that are being edited
- virtual void
- Refresh () = 0;
-
// Called when an input reader should relinquish its control so another
// can be pushed onto the IO handler stack, or so the current IO
// handler can pop itself off the stack
@@ -246,7 +234,14 @@ namespace lldb_private {
void
WaitForPop ();
-
+
+ virtual void
+ PrintAsync (Stream *stream, const char *s, size_t len)
+ {
+ stream->Write (s, len);
+ stream->Flush();
+ }
+
protected:
Debugger &m_debugger;
lldb::StreamFileSP m_input_sp;
@@ -318,7 +313,7 @@ namespace lldb_private {
}
//------------------------------------------------------------------
- /// Called when a new line is created or one of an identifed set of
+ /// Called when a new line is created or one of an identified set of
/// indentation characters is typed.
///
/// This function determines how much indentation should be added
@@ -332,7 +327,7 @@ namespace lldb_private {
/// following the line containing the cursor are not included.
///
/// @param[in] cursor_position
- /// The number of characters preceeding the cursor on the final
+ /// The number of characters preceding the cursor on the final
/// line at the time.
///
/// @return
@@ -448,17 +443,17 @@ namespace lldb_private {
{
}
- virtual ConstString
- IOHandlerGetControlSequence (char ch)
+ ConstString
+ IOHandlerGetControlSequence (char ch) override
{
if (ch == 'd')
return ConstString (m_end_line + "\n");
return ConstString();
}
- virtual bool
+ bool
IOHandlerIsInputComplete (IOHandler &io_handler,
- StringList &lines)
+ StringList &lines) override
{
// Determine whether the end of input signal has been entered
const size_t num_lines = lines.GetSize();
@@ -507,53 +502,47 @@ namespace lldb_private {
virtual
~IOHandlerEditline ();
- virtual void
- Run ();
+ void
+ Run () override;
- virtual void
- Hide ();
-
- virtual void
- Refresh ();
-
- virtual void
- Cancel ();
+ void
+ Cancel () override;
- virtual bool
- Interrupt ();
+ bool
+ Interrupt () override;
- virtual void
- GotEOF();
+ void
+ GotEOF() override;
- virtual void
- Activate ();
+ void
+ Activate () override;
- virtual void
- Deactivate ();
+ void
+ Deactivate () override;
- virtual ConstString
- GetControlSequence (char ch)
+ ConstString
+ GetControlSequence (char ch) override
{
return m_delegate.IOHandlerGetControlSequence (ch);
}
- virtual const char *
- GetCommandPrefix ()
+ const char *
+ GetCommandPrefix () override
{
return m_delegate.IOHandlerGetCommandPrefix ();
}
- virtual const char *
- GetHelpPrologue ()
+ const char *
+ GetHelpPrologue () override
{
return m_delegate.IOHandlerGetHelpPrologue ();
}
- virtual const char *
- GetPrompt ();
+ const char *
+ GetPrompt () override;
- virtual bool
- SetPrompt (const char *prompt);
+ bool
+ SetPrompt (const char *prompt) override;
const char *
GetContinuationPrompt ();
@@ -591,6 +580,9 @@ namespace lldb_private {
uint32_t
GetCurrentLineIndex () const;
+ void
+ PrintAsync (Stream *stream, const char *s, size_t len) override;
+
private:
#ifndef LLDB_DISABLE_LIBEDIT
static bool
@@ -626,6 +618,7 @@ namespace lldb_private {
bool m_multi_line;
bool m_color_prompts;
bool m_interrupt_exits;
+ bool m_editing; // Set to true when fetching a line manually (not using libedit)
};
// The order of base classes is important. Look at the constructor of IOHandlerConfirm
@@ -648,17 +641,17 @@ namespace lldb_private {
return m_user_response;
}
- virtual int
+ int
IOHandlerComplete (IOHandler &io_handler,
const char *current_line,
const char *cursor,
const char *last_char,
int skip_first_n_matches,
int max_matches,
- StringList &matches);
+ StringList &matches) override;
- virtual void
- IOHandlerInputComplete (IOHandler &io_handler, std::string &data);
+ void
+ IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override;
protected:
const bool m_default_response;
@@ -671,32 +664,25 @@ namespace lldb_private {
public:
IOHandlerCursesGUI (Debugger &debugger);
- virtual
- ~IOHandlerCursesGUI ();
-
- virtual void
- Run ();
+ ~IOHandlerCursesGUI () override;
- virtual void
- Hide ();
+ void
+ Run () override;
- virtual void
- Refresh ();
-
- virtual void
- Cancel ();
+ void
+ Cancel () override;
- virtual bool
- Interrupt ();
+ bool
+ Interrupt () override;
- virtual void
- GotEOF();
+ void
+ GotEOF() override;
- virtual void
- Activate ();
+ void
+ Activate () override;
- virtual void
- Deactivate ();
+ void
+ Deactivate () override;
protected:
curses::ApplicationAP m_app_ap;
@@ -711,20 +697,11 @@ namespace lldb_private {
virtual
~IOHandlerCursesValueObjectList ();
- virtual void
- Run ();
-
- virtual void
- Hide ();
-
- virtual void
- Refresh ();
-
- virtual bool
- HandleInterrupt ();
+ void
+ Run () override;
- virtual void
- GotEOF();
+ void
+ GotEOF() override;
protected:
ValueObjectList m_valobj_list;
};
@@ -849,7 +826,10 @@ namespace lldb_private {
return NULL;
}
- protected:
+ void
+ PrintAsync (Stream *stream, const char *s, size_t len);
+
+ protected:
typedef std::vector<lldb::IOHandlerSP> collection;
collection m_stack;
diff --git a/include/lldb/Core/Log.h b/include/lldb/Core/Log.h
index b389946e264c..3aa4b4d48e17 100644
--- a/include/lldb/Core/Log.h
+++ b/include/lldb/Core/Log.h
@@ -22,20 +22,10 @@
#include "lldb/lldb-private.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Flags.h"
+#include "lldb/Core/Logging.h"
#include "lldb/Core/PluginInterface.h"
//----------------------------------------------------------------------
-// Logging types
-//----------------------------------------------------------------------
-#define LLDB_LOG_FLAG_STDOUT (1u << 0)
-#define LLDB_LOG_FLAG_STDERR (1u << 1)
-#define LLDB_LOG_FLAG_FATAL (1u << 2)
-#define LLDB_LOG_FLAG_ERROR (1u << 3)
-#define LLDB_LOG_FLAG_WARNING (1u << 4)
-#define LLDB_LOG_FLAG_DEBUG (1u << 5)
-#define LLDB_LOG_FLAG_VERBOSE (1u << 6)
-
-//----------------------------------------------------------------------
// Logging Options
//----------------------------------------------------------------------
#define LLDB_LOG_OPTION_THREADSAFE (1u << 0)
@@ -46,6 +36,7 @@
#define LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD (1u << 5)
#define LLDB_LOG_OPTION_PREPEND_THREAD_NAME (1U << 6)
#define LLDB_LOG_OPTION_BACKTRACE (1U << 7)
+#define LLDB_LOG_OPTION_APPEND (1U << 8)
//----------------------------------------------------------------------
// Logging Functions
@@ -59,12 +50,10 @@ public:
//------------------------------------------------------------------
// Callback definitions for abstracted plug-in log access.
//------------------------------------------------------------------
- typedef void (*DisableCallback) (const char **categories, Stream *feedback_strm);
- typedef Log * (*EnableCallback) (lldb::StreamSP &log_stream_sp,
- uint32_t log_options,
- const char **categories,
- Stream *feedback_strm);
- typedef void (*ListCategoriesCallback) (Stream *strm);
+ typedef void (*DisableCallback)(const char **categories, Stream *feedback_strm);
+ typedef Log *(*EnableCallback)(lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories,
+ Stream *feedback_strm);
+ typedef void (*ListCategoriesCallback)(Stream *strm);
struct Callbacks
{
@@ -77,86 +66,85 @@ public:
// Static accessors for logging channels
//------------------------------------------------------------------
static void
- RegisterLogChannel (const ConstString &channel,
- const Log::Callbacks &log_callbacks);
+ RegisterLogChannel(const ConstString &channel, const Log::Callbacks &log_callbacks);
static bool
- UnregisterLogChannel (const ConstString &channel);
+ UnregisterLogChannel(const ConstString &channel);
static bool
- GetLogChannelCallbacks (const ConstString &channel,
- Log::Callbacks &log_callbacks);
+ GetLogChannelCallbacks(const ConstString &channel, Log::Callbacks &log_callbacks);
+ static bool
+ EnableLogChannel(lldb::StreamSP &log_stream_sp, uint32_t log_options, const char *channel,
+ const char **categories, Stream &error_stream);
static void
- EnableAllLogChannels (lldb::StreamSP &log_stream_sp,
- uint32_t log_options,
- const char **categories,
- Stream *feedback_strm);
+ EnableAllLogChannels(lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories,
+ Stream *feedback_strm);
static void
- DisableAllLogChannels (Stream *feedback_strm);
+ DisableAllLogChannels(Stream *feedback_strm);
static void
- ListAllLogChannels (Stream *strm);
+ ListAllLogChannels(Stream *strm);
static void
- Initialize ();
+ Initialize();
static void
- Terminate ();
-
+ Terminate();
+
//------------------------------------------------------------------
// Auto completion
//------------------------------------------------------------------
static void
- AutoCompleteChannelName (const char *channel_name,
- StringList &matches);
+ AutoCompleteChannelName(const char *channel_name, StringList &matches);
//------------------------------------------------------------------
// Member functions
//------------------------------------------------------------------
- Log ();
+ Log();
- Log (const lldb::StreamSP &stream_sp);
+ Log(const lldb::StreamSP &stream_sp);
- ~Log ();
+ virtual
+ ~Log();
- void
- PutCString (const char *cstr);
+ virtual void
+ PutCString(const char *cstr);
- void
- Printf (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+ virtual void
+ Printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
- void
- VAPrintf (const char *format, va_list args);
+ virtual void
+ VAPrintf(const char *format, va_list args);
- void
- PrintfWithFlags( uint32_t flags, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
+ virtual void
+ LogIf(uint32_t mask, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
- void
- LogIf (uint32_t mask, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
+ virtual void
+ Debug(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
- void
- Debug (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+ virtual void
+ DebugVerbose(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
- void
- DebugVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+ virtual void
+ Error(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
- void
- Error (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+ virtual void
+ VAError(const char *format, va_list args);
- void
- FatalError (int err, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
+ virtual void
+ FatalError(int err, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
- void
- Verbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+ virtual void
+ Verbose(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
- void
- Warning (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+ virtual void
+ Warning(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
- void
- WarningVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+ virtual void
+ WarningVerbose(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
Flags &
GetOptions();
@@ -177,7 +165,7 @@ public:
GetDebug() const;
void
- SetStream (const lldb::StreamSP &stream_sp)
+ SetStream(const lldb::StreamSP &stream_sp)
{
m_stream_sp = stream_sp;
}
@@ -190,43 +178,35 @@ protected:
Flags m_options;
Flags m_mask_bits;
- void
- PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args);
-
private:
- DISALLOW_COPY_AND_ASSIGN (Log);
+ DISALLOW_COPY_AND_ASSIGN(Log);
};
class LogChannel : public PluginInterface
{
public:
- LogChannel ();
+ LogChannel();
- virtual
- ~LogChannel ();
+ virtual ~LogChannel();
- static lldb::LogChannelSP
- FindPlugin (const char *plugin_name);
+ static lldb::LogChannelSP FindPlugin(const char *plugin_name);
// categories is a an array of chars that ends with a NULL element.
- virtual void
- Disable (const char **categories, Stream *feedback_strm) = 0;
+ virtual void Disable(const char **categories, Stream *feedback_strm) = 0;
- virtual bool
- Enable (lldb::StreamSP &log_stream_sp,
- uint32_t log_options,
- Stream *feedback_strm, // Feedback stream for argument errors etc
- const char **categories) = 0;// The categories to enable within this logging stream, if empty, enable default set
+ virtual bool Enable(
+ lldb::StreamSP &log_stream_sp, uint32_t log_options,
+ Stream *feedback_strm, // Feedback stream for argument errors etc
+ const char **categories) = 0; // The categories to enable within this logging stream, if empty, enable default set
- virtual void
- ListCategories (Stream *strm) = 0;
+ virtual void ListCategories(Stream *strm) = 0;
protected:
std::unique_ptr<Log> m_log_ap;
private:
- DISALLOW_COPY_AND_ASSIGN (LogChannel);
+ DISALLOW_COPY_AND_ASSIGN(LogChannel);
};
diff --git a/include/lldb/lldb-private-log.h b/include/lldb/Core/Logging.h
index dc37ae2c7c42..a4dd76f11237 100644
--- a/include/lldb/lldb-private-log.h
+++ b/include/lldb/Core/Logging.h
@@ -1,4 +1,4 @@
-//===-- lldb-private-log.h --------------------------------------*- C++ -*-===//
+//===-- Logging.h -----------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef liblldb_lldb_private_log_h_
-#define liblldb_lldb_private_log_h_
+#ifndef liblldb_Core_Logging_h_
+#define liblldb_Core_Logging_h_
// C Includes
// C++ Includes
@@ -47,6 +47,7 @@
#define LIBLLDB_LOG_PLATFORM (1u << 25)
#define LIBLLDB_LOG_SYSTEM_RUNTIME (1u << 26)
#define LIBLLDB_LOG_JIT_LOADER (1u << 27)
+#define LIBLLDB_LOG_LANGUAGE (1u << 28)
#define LIBLLDB_LOG_ALL (UINT32_MAX)
#define LIBLLDB_LOG_DEFAULT (LIBLLDB_LOG_PROCESS |\
LIBLLDB_LOG_THREAD |\
@@ -90,4 +91,4 @@ ListLogCategories (Stream *strm);
} // namespace lldb_private
-#endif // liblldb_lldb_private_log_h_
+#endif // liblldb_Core_Logging_h_
diff --git a/include/lldb/Core/Mangled.h b/include/lldb/Core/Mangled.h
index 87b23799882f..a2a2b5591d0f 100644
--- a/include/lldb/Core/Mangled.h
+++ b/include/lldb/Core/Mangled.h
@@ -41,6 +41,13 @@ public:
ePreferDemangledWithoutArguments
};
+ enum ManglingScheme
+ {
+ eManglingSchemeNone = 0,
+ eManglingSchemeMSVC,
+ eManglingSchemeItanium
+ };
+
//----------------------------------------------------------------------
/// Default constructor.
///
@@ -291,12 +298,12 @@ public:
SetValue (const ConstString &name);
//----------------------------------------------------------------------
- /// Get the language only if it is definitive what the language is from
- /// the mangling.
+ /// Try to guess the language from the mangling.
///
/// For a mangled name to have a language it must have both a mangled
- /// and a demangled name and it must be definitive from the mangling
- /// what the language is.
+ /// and a demangled name and it can be guessed from the mangling what
+ /// the language is. Note: this will return C++ for any language that
+ /// uses Itanium ABI mangling.
///
/// Standard C function names will return eLanguageTypeUnknown because
/// they aren't mangled and it isn't clear what language the name
@@ -307,7 +314,7 @@ public:
/// if there is no mangled or demangled counterpart.
//----------------------------------------------------------------------
lldb::LanguageType
- GetLanguage ();
+ GuessLanguage () const;
private:
//----------------------------------------------------------------------
diff --git a/include/lldb/Core/Module.h b/include/lldb/Core/Module.h
index 60fbb989502e..127ddaeb9fd4 100644
--- a/include/lldb/Core/Module.h
+++ b/include/lldb/Core/Module.h
@@ -10,12 +10,12 @@
#ifndef liblldb_Module_h_
#define liblldb_Module_h_
+#include "lldb/lldb-forward.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/UUID.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Host/TimeValue.h"
-#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/SymbolContextScope.h"
#include "lldb/Target/PathMappingList.h"
@@ -1098,7 +1098,7 @@ protected:
mutable Mutex m_mutex; ///< A mutex to keep this object happy in multi-threaded environments.
TimeValue m_mod_time; ///< The modification time for this module when it was created.
ArchSpec m_arch; ///< The architecture for this module.
- lldb_private::UUID m_uuid; ///< Each module is assumed to have a unique identifier to help match it up to debug symbols.
+ UUID m_uuid; ///< Each module is assumed to have a unique identifier to help match it up to debug symbols.
FileSpec m_file; ///< The file representation on disk for this module (if there is one).
FileSpec m_platform_file;///< The path to the module on the platform on which it is being debugged
FileSpec m_remote_install_file; ///< If set when debugging on remote platforms, this module will be installed at this location
@@ -1107,10 +1107,12 @@ protected:
uint64_t m_object_offset;
TimeValue m_object_mod_time;
lldb::ObjectFileSP m_objfile_sp; ///< A shared pointer to the object file parser for this module as it may or may not be shared with the SymbolFile
- std::unique_ptr<SymbolVendor> m_symfile_ap; ///< A pointer to the symbol vendor for this module.
- ClangASTContext m_ast; ///< The AST context for this module.
+ lldb::SymbolVendorUP m_symfile_ap; ///< A pointer to the symbol vendor for this module.
+ std::vector<lldb::SymbolVendorUP> m_old_symfiles; ///< If anyone calls Module::SetSymbolFileFileSpec() and changes the symbol file,
+ ///< we need to keep all old symbol files around in case anyone has type references to them
+ lldb::ClangASTContextUP m_ast; ///< The AST context for this module.
PathMappingList m_source_mappings; ///< Module specific source remappings for when you have debug info for a module that doesn't match where the sources currently are
- std::unique_ptr<lldb_private::SectionList> m_sections_ap; ///< Unified section list for module that is used by the ObjectFile and and ObjectFile instances for the debug info
+ lldb::SectionListUP m_sections_ap; ///< Unified section list for module that is used by the ObjectFile and and ObjectFile instances for the debug info
bool m_did_load_objfile:1,
m_did_load_symbol_vendor:1,
diff --git a/include/lldb/Core/ModuleList.h b/include/lldb/Core/ModuleList.h
index a46e212da9bb..f4c12cf168ac 100644
--- a/include/lldb/Core/ModuleList.h
+++ b/include/lldb/Core/ModuleList.h
@@ -12,6 +12,7 @@
#include <vector>
#include <list>
+#include <functional>
#include "lldb/lldb-private.h"
#include "lldb/Host/Mutex.h"
@@ -562,6 +563,9 @@ public:
static bool
RemoveSharedModuleIfOrphaned (const Module *module_ptr);
+ void
+ ForEach (std::function <bool (const lldb::ModuleSP &module_sp)> const &callback) const;
+
protected:
//------------------------------------------------------------------
// Class typedefs.
diff --git a/include/lldb/Core/ModuleSpec.h b/include/lldb/Core/ModuleSpec.h
index 195fd991f8de..be7041981a0a 100644
--- a/include/lldb/Core/ModuleSpec.h
+++ b/include/lldb/Core/ModuleSpec.h
@@ -14,6 +14,7 @@
#include "lldb/Core/Stream.h"
#include "lldb/Core/UUID.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Mutex.h"
#include "lldb/Target/PathMappingList.h"
namespace lldb_private {
@@ -29,6 +30,7 @@ public:
m_uuid (),
m_object_name (),
m_object_offset (0),
+ m_object_size (0),
m_object_mod_time (),
m_source_mappings ()
{
@@ -42,6 +44,7 @@ public:
m_uuid (),
m_object_name (),
m_object_offset (0),
+ m_object_size (file_spec.GetByteSize ()),
m_object_mod_time (),
m_source_mappings ()
{
@@ -55,6 +58,7 @@ public:
m_uuid (),
m_object_name (),
m_object_offset (0),
+ m_object_size (file_spec.GetByteSize ()),
m_object_mod_time (),
m_source_mappings ()
{
@@ -68,6 +72,7 @@ public:
m_uuid (rhs.m_uuid),
m_object_name (rhs.m_object_name),
m_object_offset (rhs.m_object_offset),
+ m_object_size (rhs.m_object_size),
m_object_mod_time (rhs.m_object_mod_time),
m_source_mappings (rhs.m_source_mappings)
{
@@ -85,6 +90,7 @@ public:
m_uuid = rhs.m_uuid;
m_object_name = rhs.m_object_name;
m_object_offset = rhs.m_object_offset;
+ m_object_size = rhs.m_object_size;
m_object_mod_time = rhs.m_object_mod_time;
m_source_mappings = rhs.m_source_mappings;
}
@@ -254,7 +260,19 @@ public:
{
m_object_offset = object_offset;
}
-
+
+ uint64_t
+ GetObjectSize () const
+ {
+ return m_object_size;
+ }
+
+ void
+ SetObjectSize (uint64_t object_size)
+ {
+ m_object_size = object_size;
+ }
+
TimeValue &
GetObjectModificationTime ()
{
@@ -283,6 +301,7 @@ public:
m_uuid.Clear();
m_object_name.Clear();
m_object_offset = 0;
+ m_object_size = 0;
m_source_mappings.Clear(false);
m_object_mod_time.Clear();
}
@@ -302,6 +321,8 @@ public:
return true;
if (m_object_name)
return true;
+ if (m_object_size)
+ return true;
if (m_object_mod_time.IsValid())
return true;
return false;
@@ -362,7 +383,14 @@ public:
{
if (dumped_something)
strm.PutCString(", ");
- strm.Printf("object_offset = 0x%" PRIx64, m_object_offset);
+ strm.Printf("object_offset = %" PRIu64, m_object_offset);
+ dumped_something = true;
+ }
+ if (m_object_size > 0)
+ {
+ if (dumped_something)
+ strm.PutCString(", ");
+ strm.Printf("object size = %" PRIu64, m_object_size);
dumped_something = true;
}
if (m_object_mod_time.IsValid())
@@ -425,6 +453,7 @@ protected:
UUID m_uuid;
ConstString m_object_name;
uint64_t m_object_offset;
+ uint64_t m_object_size;
TimeValue m_object_mod_time;
mutable PathMappingList m_source_mappings;
};
diff --git a/include/lldb/Core/PluginManager.h b/include/lldb/Core/PluginManager.h
index 55e6df06d842..af940d788ab0 100644
--- a/include/lldb/Core/PluginManager.h
+++ b/include/lldb/Core/PluginManager.h
@@ -137,7 +137,8 @@ public:
static bool
RegisterPlugin (const ConstString &name,
const char *description,
- LanguageRuntimeCreateInstance create_callback);
+ LanguageRuntimeCreateInstance create_callback,
+ LanguageRuntimeGetCommandObject command_callback = nullptr);
static bool
UnregisterPlugin (LanguageRuntimeCreateInstance create_callback);
@@ -145,6 +146,9 @@ public:
static LanguageRuntimeCreateInstance
GetLanguageRuntimeCreateCallbackAtIndex (uint32_t idx);
+ static LanguageRuntimeGetCommandObject
+ GetLanguageRuntimeGetCommandObjectAtIndex (uint32_t idx);
+
static LanguageRuntimeCreateInstance
GetLanguageRuntimeCreateCallbackForPluginName (const ConstString &name);
diff --git a/include/lldb/Core/RangeMap.h b/include/lldb/Core/RangeMap.h
index d78504c7d285..d2c43a5d794d 100644
--- a/include/lldb/Core/RangeMap.h
+++ b/include/lldb/Core/RangeMap.h
@@ -128,9 +128,10 @@ namespace lldb_private {
{
return Contains(range.GetRangeBase()) && ContainsEndInclusive(range.GetRangeEnd());
}
-
+
+ // Returns true if the two ranges adjoing or intersect
bool
- Overlap (const Range &rhs) const
+ DoesAdjoinOrIntersect (const Range &rhs) const
{
const BaseType lhs_base = this->GetRangeBase();
const BaseType rhs_base = rhs.GetRangeBase();
@@ -139,7 +140,19 @@ namespace lldb_private {
bool result = (lhs_base <= rhs_end) && (lhs_end >= rhs_base);
return result;
}
-
+
+ // Returns true if the two ranges intersect
+ bool
+ DoesIntersect (const Range &rhs) const
+ {
+ const BaseType lhs_base = this->GetRangeBase();
+ const BaseType rhs_base = rhs.GetRangeBase();
+ const BaseType lhs_end = this->GetRangeEnd();
+ const BaseType rhs_end = rhs.GetRangeEnd();
+ bool result = (lhs_base < rhs_end) && (lhs_end > rhs_base);
+ return result;
+ }
+
bool
operator < (const Range &rhs) const
{
@@ -241,7 +254,7 @@ namespace lldb_private {
// don't end up allocating and making a new collection for no reason
for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
{
- if (prev != end && prev->Overlap(*pos))
+ if (prev != end && prev->DoesAdjoinOrIntersect(*pos))
{
can_combine = true;
break;
@@ -255,7 +268,7 @@ namespace lldb_private {
Collection minimal_ranges;
for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
{
- if (prev != end && prev->Overlap(*pos))
+ if (prev != end && prev->DoesAdjoinOrIntersect(*pos))
minimal_ranges.back().SetRangeEnd (std::max<BaseType>(prev->GetRangeEnd(), pos->GetRangeEnd()));
else
minimal_ranges.push_back (*pos);
@@ -521,7 +534,7 @@ namespace lldb_private {
// don't end up allocating and making a new collection for no reason
for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
{
- if (prev != end && prev->Overlap(*pos))
+ if (prev != end && prev->DoesAdjoinOrIntersect(*pos))
{
can_combine = true;
break;
@@ -535,7 +548,7 @@ namespace lldb_private {
Collection minimal_ranges;
for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
{
- if (prev != end && prev->Overlap(*pos))
+ if (prev != end && prev->DoesAdjoinOrIntersect(*pos))
minimal_ranges.back().SetRangeEnd (std::max<BaseType>(prev->GetRangeEnd(), pos->GetRangeEnd()));
else
minimal_ranges.push_back (*pos);
diff --git a/include/lldb/Core/StreamAsynchronousIO.h b/include/lldb/Core/StreamAsynchronousIO.h
index a73a9567fe83..d3b054463fa7 100644
--- a/include/lldb/Core/StreamAsynchronousIO.h
+++ b/include/lldb/Core/StreamAsynchronousIO.h
@@ -20,7 +20,7 @@ class StreamAsynchronousIO :
public Stream
{
public:
- StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type);
+ StreamAsynchronousIO (Debugger &debugger, bool for_stdout);
virtual ~StreamAsynchronousIO ();
@@ -32,9 +32,9 @@ public:
private:
- Broadcaster &m_broadcaster;
- uint32_t m_broadcast_event_type;
- std::string m_accumulated_data;
+ Debugger &m_debugger;
+ std::string m_data;
+ bool m_for_stdout;
};
} // namespace lldb_private
diff --git a/include/lldb/Core/StreamFile.h b/include/lldb/Core/StreamFile.h
index d032c0b21e6b..55bb361780a5 100644
--- a/include/lldb/Core/StreamFile.h
+++ b/include/lldb/Core/StreamFile.h
@@ -37,6 +37,10 @@ public:
StreamFile (const char *path);
+ StreamFile (const char *path,
+ uint32_t options,
+ uint32_t permissions = lldb::eFilePermissionsFileDefault);
+
StreamFile (FILE *fh, bool transfer_ownership);
virtual
diff --git a/include/lldb/Core/StringList.h b/include/lldb/Core/StringList.h
index b68ab4be2d6d..c69ed872c30d 100644
--- a/include/lldb/Core/StringList.h
+++ b/include/lldb/Core/StringList.h
@@ -14,6 +14,7 @@
#include "lldb/Core/STLUtils.h"
#include "lldb/lldb-forward.h"
+#include "llvm/ADT/StringRef.h"
namespace lldb_private {
@@ -43,6 +44,9 @@ public:
AppendString (const char *str, size_t str_len);
void
+ AppendString(llvm::StringRef str);
+
+ void
AppendList (const char ** strv, int strc);
void
diff --git a/include/lldb/Core/StructuredData.h b/include/lldb/Core/StructuredData.h
index a4cabf4fe352..8acfa310deac 100644
--- a/include/lldb/Core/StructuredData.h
+++ b/include/lldb/Core/StructuredData.h
@@ -13,10 +13,11 @@
// C Includes
// C++ Includes
+#include <functional>
#include <map>
+#include <string>
#include <utility>
#include <vector>
-#include <string>
#include "llvm/ADT/StringRef.h"
@@ -54,14 +55,22 @@ public:
class Boolean;
class String;
class Dictionary;
+ class Generic;
typedef std::shared_ptr<Object> ObjectSP;
typedef std::shared_ptr<Array> ArraySP;
+ typedef std::shared_ptr<Integer> IntegerSP;
+ typedef std::shared_ptr<Float> FloatSP;
+ typedef std::shared_ptr<Boolean> BooleanSP;
+ typedef std::shared_ptr<String> StringSP;
typedef std::shared_ptr<Dictionary> DictionarySP;
+ typedef std::shared_ptr<Generic> GenericSP;
- enum class Type {
+ enum class Type
+ {
eTypeInvalid = -1,
eTypeNull = 0,
+ eTypeGeneric,
eTypeArray,
eTypeInteger,
eTypeFloat,
@@ -84,6 +93,12 @@ public:
{
}
+ virtual bool
+ IsValid() const
+ {
+ return true;
+ }
+
virtual void
Clear ()
{
@@ -126,6 +141,15 @@ public:
return NULL;
}
+ uint64_t
+ GetIntegerValue (uint64_t fail_value = 0)
+ {
+ Integer *integer = GetAsInteger ();
+ if (integer)
+ return integer->GetValue();
+ return fail_value;
+ }
+
Float *
GetAsFloat ()
{
@@ -134,6 +158,15 @@ public:
return NULL;
}
+ double
+ GetFloatValue (double fail_value = 0.0)
+ {
+ Float *f = GetAsFloat ();
+ if (f)
+ return f->GetValue();
+ return fail_value;
+ }
+
Boolean *
GetAsBoolean ()
{
@@ -142,6 +175,15 @@ public:
return NULL;
}
+ bool
+ GetBooleanValue (bool fail_value = false)
+ {
+ Boolean *b = GetAsBoolean ();
+ if (b)
+ return b->GetValue();
+ return fail_value;
+ }
+
String *
GetAsString ()
{
@@ -150,9 +192,32 @@ public:
return NULL;
}
+ std::string
+ GetStringValue(const char *fail_value = NULL)
+ {
+ String *s = GetAsString ();
+ if (s)
+ return s->GetValue();
+
+ if (fail_value && fail_value[0])
+ return std::string(fail_value);
+
+ return std::string();
+ }
+
+ Generic *
+ GetAsGeneric()
+ {
+ if (m_type == Type::eTypeGeneric)
+ return (Generic *)this;
+ return NULL;
+ }
+
ObjectSP
GetObjectForDotSeparatedPath (llvm::StringRef path);
+ void DumpToStdout() const;
+
virtual void
Dump (Stream &s) const = 0;
@@ -173,8 +238,19 @@ public:
{
}
+ void
+ ForEach (std::function <bool(Object* object)> const &foreach_callback) const
+ {
+ for (const auto &object_sp : m_items)
+ {
+ if (foreach_callback(object_sp.get()) == false)
+ break;
+ }
+ }
+
+
size_t
- GetSize()
+ GetSize() const
{
return m_items.size();
}
@@ -188,13 +264,97 @@ public:
}
ObjectSP
- GetItemAtIndex (size_t idx)
+ GetItemAtIndex(size_t idx) const
{
+ assert(idx < GetSize());
if (idx < m_items.size())
return m_items[idx];
return ObjectSP();
}
+ template <class IntType>
+ bool
+ GetItemAtIndexAsInteger(size_t idx, IntType &result) const
+ {
+ ObjectSP value = GetItemAtIndex(idx);
+ if (auto int_value = value->GetAsInteger())
+ {
+ result = static_cast<IntType>(int_value->GetValue());
+ return true;
+ }
+ return false;
+ }
+
+ template <class IntType>
+ bool
+ GetItemAtIndexAsInteger(size_t idx, IntType &result, IntType default_val) const
+ {
+ bool success = GetItemAtIndexAsInteger(idx, result);
+ if (!success)
+ result = default_val;
+ return success;
+ }
+
+ bool
+ GetItemAtIndexAsString(size_t idx, std::string &result) const
+ {
+ ObjectSP value = GetItemAtIndex(idx);
+ if (auto string_value = value->GetAsString())
+ {
+ result = string_value->GetValue();
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ GetItemAtIndexAsString(size_t idx, std::string &result, const std::string &default_val) const
+ {
+ bool success = GetItemAtIndexAsString(idx, result);
+ if (!success)
+ result = default_val;
+ return success;
+ }
+
+ bool
+ GetItemAtIndexAsString(size_t idx, ConstString &result) const
+ {
+ ObjectSP value = GetItemAtIndex(idx);
+ if (!value)
+ return false;
+ if (auto string_value = value->GetAsString())
+ {
+ result = ConstString(string_value->GetValue());
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ GetItemAtIndexAsString(size_t idx, ConstString &result, const char *default_val) const
+ {
+ bool success = GetItemAtIndexAsString(idx, result);
+ if (!success)
+ result.SetCString(default_val);
+ return success;
+ }
+
+ bool
+ GetItemAtIndexAsDictionary(size_t idx, Dictionary *&result) const
+ {
+ ObjectSP value = GetItemAtIndex(idx);
+ result = value->GetAsDictionary();
+ return (result != nullptr);
+ }
+
+ bool
+ GetItemAtIndexAsArray(size_t idx, Array *&result) const
+ {
+ ObjectSP value = GetItemAtIndex(idx);
+ result = value->GetAsArray();
+ return (result != nullptr);
+ }
+
void
Push(ObjectSP item)
{
@@ -207,8 +367,7 @@ public:
m_items.push_back(item);
}
- virtual void
- Dump (Stream &s) const;
+ void Dump(Stream &s) const override;
protected:
typedef std::vector<ObjectSP> collection;
@@ -219,9 +378,9 @@ public:
class Integer : public Object
{
public:
- Integer () :
+ Integer (uint64_t i = 0) :
Object (Type::eTypeInteger),
- m_value ()
+ m_value (i)
{
}
@@ -241,8 +400,7 @@ public:
return m_value;
}
- virtual void
- Dump (Stream &s) const;
+ void Dump(Stream &s) const override;
protected:
uint64_t m_value;
@@ -251,9 +409,9 @@ public:
class Float : public Object
{
public:
- Float () :
+ Float (double d = 0.0) :
Object (Type::eTypeFloat),
- m_value ()
+ m_value (d)
{
}
@@ -273,8 +431,7 @@ public:
return m_value;
}
- virtual void
- Dump (Stream &s) const;
+ void Dump(Stream &s) const override;
protected:
double m_value;
@@ -283,9 +440,9 @@ public:
class Boolean : public Object
{
public:
- Boolean () :
+ Boolean (bool b = false) :
Object (Type::eTypeBoolean),
- m_value ()
+ m_value (b)
{
}
@@ -305,8 +462,7 @@ public:
return m_value;
}
- virtual void
- Dump (Stream &s) const;
+ void Dump(Stream &s) const override;
protected:
bool m_value;
@@ -317,26 +473,39 @@ public:
class String : public Object
{
public:
- String () :
+ String (const char *cstr = NULL) :
Object (Type::eTypeString),
m_value ()
{
+ if (cstr)
+ m_value = cstr;
+ }
+
+ String (const std::string &s) :
+ Object (Type::eTypeString),
+ m_value (s)
+ {
+ }
+
+ String (const std::string &&s) :
+ Object (Type::eTypeString),
+ m_value (s)
+ {
}
void
- SetValue (std::string string)
+ SetValue (const std::string &string)
{
m_value = string;
}
- std::string
+ const std::string &
GetValue ()
{
return m_value;
}
- virtual void
- Dump (Stream &s) const;
+ void Dump(Stream &s) const override;
protected:
std::string m_value;
@@ -345,6 +514,7 @@ public:
class Dictionary : public Object
{
public:
+
Dictionary () :
Object (Type::eTypeDictionary),
m_dict ()
@@ -354,14 +524,25 @@ public:
virtual ~Dictionary()
{
}
+
size_t
- GetSize()
+ GetSize() const
{
return m_dict.size();
}
+ void
+ ForEach (std::function <bool(ConstString key, Object* object)> const &callback) const
+ {
+ for (const auto &pair : m_dict)
+ {
+ if (callback (pair.first, pair.second.get()) == false)
+ break;
+ }
+ }
+
ObjectSP
- GetKeys()
+ GetKeys() const
{
ObjectSP object_sp(new Array ());
Array *array = object_sp->GetAsArray();
@@ -376,10 +557,10 @@ public:
}
ObjectSP
- GetValueForKey (const char *key)
+ GetValueForKey(llvm::StringRef key) const
{
ObjectSP value_sp;
- if (key)
+ if (!key.empty())
{
ConstString key_cs(key);
for (collection::const_iterator iter = m_dict.begin(); iter != m_dict.end(); ++iter)
@@ -394,62 +575,144 @@ public:
return value_sp;
}
+ template <class IntType>
bool
- HasKey (const char *key)
+ GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const
{
- ConstString key_cs (key);
- collection::const_iterator search = m_dict.find(key_cs);
- if (search != m_dict.end())
+ ObjectSP value = GetValueForKey(key);
+ if (!value)
+ return false;
+ if (auto int_value = value->GetAsInteger())
{
+ result = static_cast<IntType>(int_value->GetValue());
return true;
}
- else
+ return false;
+ }
+
+ template <class IntType>
+ bool
+ GetValueForKeyAsInteger(llvm::StringRef key, IntType &result, IntType default_val) const
+ {
+ bool success = GetValueForKeyAsInteger<IntType>(key, result);
+ if (!success)
+ result = default_val;
+ return success;
+ }
+
+ bool
+ GetValueForKeyAsString(llvm::StringRef key, std::string &result) const
+ {
+ ObjectSP value = GetValueForKey(key);
+ if (!value)
+ return false;
+ if (auto string_value = value->GetAsString())
{
+ result = string_value->GetValue();
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ GetValueForKeyAsString(llvm::StringRef key, std::string &result, const char *default_val) const
+ {
+ bool success = GetValueForKeyAsString(key, result);
+ if (!success)
+ {
+ if (default_val)
+ result = default_val;
+ else
+ result.clear();
+ }
+ return success;
+ }
+
+ bool
+ GetValueForKeyAsString(llvm::StringRef key, ConstString &result) const
+ {
+ ObjectSP value = GetValueForKey(key);
+ if (!value)
return false;
+ if (auto string_value = value->GetAsString())
+ {
+ result = ConstString(string_value->GetValue());
+ return true;
}
+ return false;
+ }
+
+ bool
+ GetValueForKeyAsString(llvm::StringRef key, ConstString &result, const char *default_val) const
+ {
+ bool success = GetValueForKeyAsString(key, result);
+ if (!success)
+ result.SetCString(default_val);
+ return success;
+ }
+
+ bool
+ GetValueForKeyAsDictionary(llvm::StringRef key, Dictionary *&result) const
+ {
+ result = nullptr;
+ ObjectSP value = GetValueForKey(key);
+ if (!value)
+ return false;
+ result = value->GetAsDictionary();
+ return true;
+ }
+
+ bool
+ GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const
+ {
+ result = nullptr;
+ ObjectSP value = GetValueForKey(key);
+ if (!value)
+ return false;
+ result = value->GetAsArray();
+ return true;
+ }
+
+ bool
+ HasKey(llvm::StringRef key) const
+ {
+ ConstString key_cs(key);
+ collection::const_iterator search = m_dict.find(key_cs);
+ return search != m_dict.end();
}
void
- AddItem (const char *key, ObjectSP value)
+ AddItem (llvm::StringRef key, ObjectSP value)
{
ConstString key_cs(key);
m_dict[key_cs] = value;
}
void
- AddIntegerItem (const char *key, uint64_t value)
+ AddIntegerItem (llvm::StringRef key, uint64_t value)
{
- ObjectSP val_obj (new Integer());
- val_obj->GetAsInteger()->SetValue (value);
- AddItem (key, val_obj);
+ AddItem (key, ObjectSP (new Integer(value)));
}
void
- AddFloatItem (const char *key, double value)
+ AddFloatItem (llvm::StringRef key, double value)
{
- ObjectSP val_obj (new Float());
- val_obj->GetAsFloat()->SetValue (value);
- AddItem (key, val_obj);
+ AddItem (key, ObjectSP (new Float(value)));
}
void
- AddStringItem (const char *key, std::string value)
+ AddStringItem (llvm::StringRef key, std::string value)
{
- ObjectSP val_obj (new String());
- val_obj->GetAsString()->SetValue (value);
- AddItem (key, val_obj);
+ AddItem (key, ObjectSP (new String(std::move(value))));
}
void
- AddBooleanItem (const char *key, bool value)
+ AddBooleanItem (llvm::StringRef key, bool value)
{
- ObjectSP val_obj (new Boolean());
- val_obj->GetAsBoolean()->SetValue (value);
- AddItem (key, val_obj);
+ AddItem (key, ObjectSP (new Boolean(value)));
}
- virtual void
- Dump (Stream &s) const;
+ void Dump(Stream &s) const override;
protected:
typedef std::map<ConstString, ObjectSP> collection;
@@ -468,12 +731,49 @@ public:
{
}
- virtual void
- Dump (Stream &s) const;
+ bool
+ IsValid() const override
+ {
+ return false;
+ }
+
+ void Dump(Stream &s) const override;
protected:
};
+ class Generic : public Object
+ {
+ public:
+ explicit Generic(void *object = nullptr) :
+ Object (Type::eTypeGeneric),
+ m_object (object)
+ {
+ }
+
+ void
+ SetValue(void *value)
+ {
+ m_object = value;
+ }
+
+ void *
+ GetValue() const
+ {
+ return m_object;
+ }
+
+ bool
+ IsValid() const override
+ {
+ return m_object != nullptr;
+ }
+
+ void Dump(Stream &s) const override;
+
+ private:
+ void *m_object;
+ };
static ObjectSP
ParseJSON (std::string json_text);
diff --git a/include/lldb/Core/ThreadSafeDenseSet.h b/include/lldb/Core/ThreadSafeDenseSet.h
new file mode 100644
index 000000000000..19c67b65e8c1
--- /dev/null
+++ b/include/lldb/Core/ThreadSafeDenseSet.h
@@ -0,0 +1,65 @@
+//===-- ThreadSafeDenseSet.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_ThreadSafeDenseSet_h_
+#define liblldb_ThreadSafeDenseSet_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+#include "llvm/ADT/DenseSet.h"
+
+// Project includes
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+ template <typename _ElementType>
+ class ThreadSafeDenseSet
+ {
+ public:
+ typedef llvm::DenseSet<_ElementType> LLVMSetType;
+
+ ThreadSafeDenseSet(unsigned set_initial_capacity = 0,
+ Mutex::Type mutex_type = Mutex::eMutexTypeNormal) :
+ m_set(set_initial_capacity),
+ m_mutex(mutex_type)
+ {
+ }
+
+ void
+ Insert (_ElementType e)
+ {
+ Mutex::Locker locker(m_mutex);
+ m_set.insert(e);
+ }
+
+ void
+ Erase (_ElementType e)
+ {
+ Mutex::Locker locker(m_mutex);
+ m_set.erase(e);
+ }
+
+ bool
+ Lookup (_ElementType e)
+ {
+ Mutex::Locker locker(m_mutex);
+ return (m_set.count(e) > 0);
+ }
+
+ protected:
+ LLVMSetType m_set;
+ Mutex m_mutex;
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadSafeDenseSet_h_
diff --git a/include/lldb/Core/ValueObject.h b/include/lldb/Core/ValueObject.h
index b50adfb69564..cdc507093b28 100644
--- a/include/lldb/Core/ValueObject.h
+++ b/include/lldb/Core/ValueObject.h
@@ -16,6 +16,7 @@
#include <vector>
// Other libraries and framework includes
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
// Project includes
@@ -26,6 +27,7 @@
#include "lldb/Core/ConstString.h"
#include "lldb/Core/UserID.h"
#include "lldb/Core/Value.h"
+#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/Process.h"
@@ -139,19 +141,27 @@ public:
struct GetValueForExpressionPathOptions
{
+ enum class SyntheticChildrenTraversal
+ {
+ None,
+ ToSynthetic,
+ FromSynthetic,
+ Both
+ };
+
bool m_check_dot_vs_arrow_syntax;
bool m_no_fragile_ivar;
bool m_allow_bitfields_syntax;
- bool m_no_synthetic_children;
+ SyntheticChildrenTraversal m_synthetic_children_traversal;
GetValueForExpressionPathOptions(bool dot = false,
bool no_ivar = false,
bool bitfield = true,
- bool no_synth = false) :
+ SyntheticChildrenTraversal synth_traverse = SyntheticChildrenTraversal::ToSynthetic) :
m_check_dot_vs_arrow_syntax(dot),
m_no_fragile_ivar(no_ivar),
m_allow_bitfields_syntax(bitfield),
- m_no_synthetic_children(no_synth)
+ m_synthetic_children_traversal(synth_traverse)
{
}
@@ -198,16 +208,9 @@ public:
}
GetValueForExpressionPathOptions&
- DoAllowSyntheticChildren()
- {
- m_no_synthetic_children = false;
- return *this;
- }
-
- GetValueForExpressionPathOptions&
- DontAllowSyntheticChildren()
+ SetSyntheticChildrenTraversal(SyntheticChildrenTraversal traverse)
{
- m_no_synthetic_children = true;
+ m_synthetic_children_traversal = traverse;
return *this;
}
@@ -282,18 +285,19 @@ public:
SetUpdated ();
bool
- NeedsUpdating()
+ NeedsUpdating(bool accept_invalid_exe_ctx)
{
- SyncWithProcessState();
+ SyncWithProcessState(accept_invalid_exe_ctx);
return m_needs_update;
}
bool
IsValid ()
{
+ const bool accept_invalid_exe_ctx = false;
if (!m_mod_id.IsValid())
return false;
- else if (SyncWithProcessState ())
+ else if (SyncWithProcessState (accept_invalid_exe_ctx))
{
if (!m_mod_id.IsValid())
return false;
@@ -315,7 +319,7 @@ public:
private:
bool
- SyncWithProcessState ();
+ SyncWithProcessState (bool accept_invalid_exe_ctx);
ProcessModID m_mod_id; // This is the stop id when this ValueObject was last evaluated.
ExecutionContextRef m_exe_ctx_ref;
@@ -647,6 +651,7 @@ public:
bool
GetValueIsValid () const;
+ // If you call this on a newly created ValueObject, it will always return false.
bool
GetValueDidChange ();
@@ -679,12 +684,6 @@ public:
GetSyntheticArrayMember (size_t index, bool can_create);
lldb::ValueObjectSP
- GetSyntheticArrayMemberFromPointer (size_t index, bool can_create);
-
- lldb::ValueObjectSP
- GetSyntheticArrayMemberFromArray (size_t index, bool can_create);
-
- lldb::ValueObjectSP
GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_create);
lldb::ValueObjectSP
@@ -853,12 +852,19 @@ public:
virtual bool
SetData (DataExtractor &data, Error &error);
- bool
+ virtual bool
GetIsConstant () const
{
return m_update_point.IsConstant();
}
+ bool
+ NeedsUpdating ()
+ {
+ const bool accept_invalid_exe_ctx = CanUpdateWithInvalidExecutionContext();
+ return m_update_point.NeedsUpdating(accept_invalid_exe_ctx);
+ }
+
void
SetIsConstant ()
{
@@ -868,7 +874,7 @@ public:
lldb::Format
GetFormat () const;
- void
+ virtual void
SetFormat (lldb::Format format)
{
if (format != m_format)
@@ -992,6 +998,9 @@ public:
//------------------------------------------------------------------
virtual bool
MightHaveChildren();
+
+ virtual bool
+ IsRuntimeSupportValue ();
protected:
typedef ClusterManager<ValueObject> ValueObjectManager;
@@ -1128,10 +1137,12 @@ protected:
m_did_calculate_complete_objc_class_type:1,
m_is_synthetic_children_generated:1;
+ friend class ValueObjectChild;
friend class ClangExpressionDeclMap; // For GetValue
friend class ClangExpressionVariable; // For SetName
friend class Target; // For SetName
friend class ValueObjectConstResultImpl;
+ friend class ValueObjectSynthetic; // For ClearUserVisibleData
//------------------------------------------------------------------
// Constructors and Destructors
@@ -1161,6 +1172,12 @@ protected:
virtual bool
UpdateValue () = 0;
+ virtual bool
+ CanUpdateWithInvalidExecutionContext ()
+ {
+ return false;
+ }
+
virtual void
CalculateDynamicValue (lldb::DynamicValueType use_dynamic);
diff --git a/include/lldb/Core/ValueObjectChild.h b/include/lldb/Core/ValueObjectChild.h
index 7bbfe8a662d1..bf8707ea3b05 100644
--- a/include/lldb/Core/ValueObjectChild.h
+++ b/include/lldb/Core/ValueObjectChild.h
@@ -83,6 +83,9 @@ public:
protected:
virtual bool
UpdateValue ();
+
+ virtual bool
+ CanUpdateWithInvalidExecutionContext ();
virtual ClangASTType
GetClangTypeImpl ()
diff --git a/include/lldb/Core/ValueObjectDynamicValue.h b/include/lldb/Core/ValueObjectDynamicValue.h
index 7607bd38137d..8d42706be166 100644
--- a/include/lldb/Core/ValueObjectDynamicValue.h
+++ b/include/lldb/Core/ValueObjectDynamicValue.h
@@ -56,6 +56,12 @@ public:
return true;
}
+ virtual bool
+ GetIsConstant () const
+ {
+ return false;
+ }
+
virtual ValueObject *
GetParent()
{
@@ -103,6 +109,12 @@ protected:
virtual bool
UpdateValue ();
+ virtual bool
+ CanUpdateWithInvalidExecutionContext ()
+ {
+ return true;
+ }
+
virtual lldb::DynamicValueType
GetDynamicValueTypeImpl ()
{
diff --git a/include/lldb/Core/ValueObjectSyntheticFilter.h b/include/lldb/Core/ValueObjectSyntheticFilter.h
index aa784add7409..88824ef4fa54 100644
--- a/include/lldb/Core/ValueObjectSyntheticFilter.h
+++ b/include/lldb/Core/ValueObjectSyntheticFilter.h
@@ -141,12 +141,27 @@ public:
}
virtual bool
+ GetIsConstant () const
+ {
+ return false;
+ }
+
+ virtual bool
SetValueFromCString (const char *value_str, Error& error);
+ virtual void
+ SetFormat (lldb::Format format);
+
protected:
virtual bool
UpdateValue ();
+ virtual bool
+ CanUpdateWithInvalidExecutionContext ()
+ {
+ return true;
+ }
+
virtual ClangASTType
GetClangTypeImpl ();
diff --git a/include/lldb/DataFormatters/CXXFormatterFunctions.h b/include/lldb/DataFormatters/CXXFormatterFunctions.h
index 53b7468bb13c..9b1a02ca0a5c 100644
--- a/include/lldb/DataFormatters/CXXFormatterFunctions.h
+++ b/include/lldb/DataFormatters/CXXFormatterFunctions.h
@@ -186,6 +186,9 @@ namespace lldb_private {
extern template bool
ObjCSELSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&);
+ bool
+ CMTimeSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options);
+
SyntheticChildrenFrontEnd* NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
SyntheticChildrenFrontEnd* NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
@@ -229,37 +232,6 @@ namespace lldb_private {
bool
LibcxxContainerSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options);
- class LibstdcppVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd
- {
- public:
- LibstdcppVectorBoolSyntheticFrontEnd (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
- ~LibstdcppVectorBoolSyntheticFrontEnd ();
- private:
- ExecutionContextRef m_exe_ctx_ref;
- uint64_t m_count;
- lldb::addr_t m_base_data_address;
- EvaluateExpressionOptions m_options;
- };
-
- SyntheticChildrenFrontEnd* LibstdcppVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
-
class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
{
public:
@@ -395,6 +367,7 @@ namespace lldb_private {
SyntheticChildrenFrontEnd* LibcxxInitializerListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+ SyntheticChildrenFrontEnd* VectorTypeSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
} // namespace formatters
} // namespace lldb_private
diff --git a/include/lldb/DataFormatters/FormatManager.h b/include/lldb/DataFormatters/FormatManager.h
index 37dae6536761..a1f4b59fb344 100644
--- a/include/lldb/DataFormatters/FormatManager.h
+++ b/include/lldb/DataFormatters/FormatManager.h
@@ -287,6 +287,7 @@ private:
ConstString m_coreservices_category_name;
ConstString m_vectortypes_category_name;
ConstString m_appkit_category_name;
+ ConstString m_coremedia_category_name;
HardcodedFormatterFinders<TypeFormatImpl> m_hardcoded_formats;
HardcodedFormatterFinders<TypeSummaryImpl> m_hardcoded_summaries;
@@ -326,6 +327,9 @@ private:
void
LoadObjCFormatters ();
+
+ void
+ LoadCoreMediaFormatters ();
void
LoadHardcodedFormatters ();
diff --git a/include/lldb/DataFormatters/TypeFormat.h b/include/lldb/DataFormatters/TypeFormat.h
index 1090d7843e53..8aa7c60b4938 100644
--- a/include/lldb/DataFormatters/TypeFormat.h
+++ b/include/lldb/DataFormatters/TypeFormat.h
@@ -115,6 +115,22 @@ namespace lldb_private {
return *this;
}
+ bool
+ GetNonCacheable () const
+ {
+ return (m_flags & lldb::eTypeOptionNonCacheable) == lldb::eTypeOptionNonCacheable;
+ }
+
+ Flags&
+ SetNonCacheable (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionNonCacheable;
+ else
+ m_flags &= ~lldb::eTypeOptionNonCacheable;
+ return *this;
+ }
+
uint32_t
GetValue ()
{
@@ -153,6 +169,11 @@ namespace lldb_private {
{
return m_flags.GetSkipReferences();
}
+ bool
+ NonCacheable () const
+ {
+ return m_flags.GetNonCacheable();
+ }
void
SetCascades (bool value)
@@ -171,6 +192,12 @@ namespace lldb_private {
{
m_flags.SetSkipReferences(value);
}
+
+ void
+ SetNonCacheable (bool value)
+ {
+ m_flags.SetNonCacheable(value);
+ }
uint32_t
GetOptions ()
diff --git a/include/lldb/DataFormatters/TypeSummary.h b/include/lldb/DataFormatters/TypeSummary.h
index 8b90dd0c4895..c2838eac27f1 100644
--- a/include/lldb/DataFormatters/TypeSummary.h
+++ b/include/lldb/DataFormatters/TypeSummary.h
@@ -25,8 +25,8 @@
#include "lldb/Core/Error.h"
#include "lldb/Core/FormatEntity.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ValueObject.h"
-#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Symbol/Type.h"
namespace lldb_private {
@@ -211,6 +211,22 @@ namespace lldb_private {
return *this;
}
+ bool
+ GetNonCacheable () const
+ {
+ return (m_flags & lldb::eTypeOptionNonCacheable) == lldb::eTypeOptionNonCacheable;
+ }
+
+ Flags&
+ SetNonCacheable (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionNonCacheable;
+ else
+ m_flags &= ~lldb::eTypeOptionNonCacheable;
+ return *this;
+ }
+
uint32_t
GetValue ()
{
@@ -252,6 +268,11 @@ namespace lldb_private {
{
return m_flags.GetSkipReferences();
}
+ bool
+ NonCacheable () const
+ {
+ return m_flags.GetNonCacheable();
+ }
virtual bool
DoesPrintChildren (ValueObject* valobj) const
@@ -319,6 +340,12 @@ namespace lldb_private {
m_flags.SetHideItemNames(value);
}
+ virtual void
+ SetNonCacheable (bool value)
+ {
+ m_flags.SetNonCacheable(value);
+ }
+
uint32_t
GetOptions ()
{
@@ -501,8 +528,8 @@ namespace lldb_private {
{
std::string m_function_name;
std::string m_python_script;
- lldb::ScriptInterpreterObjectSP m_script_function_sp;
-
+ StructuredData::ObjectSP m_script_function_sp;
+
ScriptSummaryFormat(const TypeSummaryImpl::Flags& flags,
const char *function_name,
const char* python_script = NULL);
diff --git a/include/lldb/DataFormatters/TypeSynthetic.h b/include/lldb/DataFormatters/TypeSynthetic.h
index 675c43b1f311..ff6691c9a1b8 100644
--- a/include/lldb/DataFormatters/TypeSynthetic.h
+++ b/include/lldb/DataFormatters/TypeSynthetic.h
@@ -23,6 +23,7 @@
#include "lldb/lldb-public.h"
#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ValueObject.h"
namespace lldb_private {
@@ -235,6 +236,22 @@ namespace lldb_private {
return *this;
}
+ bool
+ GetNonCacheable () const
+ {
+ return (m_flags & lldb::eTypeOptionNonCacheable) == lldb::eTypeOptionNonCacheable;
+ }
+
+ Flags&
+ SetNonCacheable (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionNonCacheable;
+ else
+ m_flags &= ~lldb::eTypeOptionNonCacheable;
+ return *this;
+ }
+
uint32_t
GetValue ()
{
@@ -276,6 +293,11 @@ namespace lldb_private {
{
return m_flags.GetSkipReferences();
}
+ bool
+ NonCacheable () const
+ {
+ return m_flags.GetNonCacheable();
+ }
void
SetCascades (bool value)
@@ -295,6 +317,12 @@ namespace lldb_private {
m_flags.SetSkipReferences(value);
}
+ void
+ SetNonCacheable (bool value)
+ {
+ m_flags.SetNonCacheable(value);
+ }
+
uint32_t
GetOptions ()
{
@@ -551,7 +579,7 @@ namespace lldb_private {
{
private:
std::string m_python_class;
- lldb::ScriptInterpreterObjectSP m_wrapper_sp;
+ StructuredData::ObjectSP m_wrapper_sp;
ScriptInterpreter *m_interpreter;
public:
diff --git a/include/lldb/DataFormatters/TypeValidator.h b/include/lldb/DataFormatters/TypeValidator.h
index b501e47943fa..d06fac01f824 100644
--- a/include/lldb/DataFormatters/TypeValidator.h
+++ b/include/lldb/DataFormatters/TypeValidator.h
@@ -115,6 +115,22 @@ public:
return *this;
}
+ bool
+ GetNonCacheable () const
+ {
+ return (m_flags & lldb::eTypeOptionNonCacheable) == lldb::eTypeOptionNonCacheable;
+ }
+
+ Flags&
+ SetNonCacheable (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionNonCacheable;
+ else
+ m_flags &= ~lldb::eTypeOptionNonCacheable;
+ return *this;
+ }
+
uint32_t
GetValue ()
{
@@ -153,6 +169,11 @@ public:
{
return m_flags.GetSkipReferences();
}
+ bool
+ NonCacheable () const
+ {
+ return m_flags.GetNonCacheable();
+ }
void
SetCascades (bool value)
@@ -172,6 +193,12 @@ public:
m_flags.SetSkipReferences(value);
}
+ void
+ SetNonCacheable (bool value)
+ {
+ m_flags.SetNonCacheable(value);
+ }
+
uint32_t
GetOptions ()
{
diff --git a/include/lldb/DataFormatters/ValueObjectPrinter.h b/include/lldb/DataFormatters/ValueObjectPrinter.h
index 235d5389ee75..dc05fd482676 100644
--- a/include/lldb/DataFormatters/ValueObjectPrinter.h
+++ b/include/lldb/DataFormatters/ValueObjectPrinter.h
@@ -75,6 +75,8 @@ struct DumpValueObjectOptions
DumpValueObjectOptions (const DumpValueObjectOptions& rhs) = default;
+ DumpValueObjectOptions (ValueObject& valobj);
+
DumpValueObjectOptions&
SetMaximumPointerDepth(uint32_t depth = 0)
{
@@ -246,6 +248,9 @@ struct DumpValueObjectOptions
class ValueObjectPrinter
{
public:
+
+ ValueObjectPrinter (ValueObject* valobj,
+ Stream* s);
ValueObjectPrinter (ValueObject* valobj,
Stream* s,
diff --git a/tools/lldb-platform/exports b/include/lldb/DataFormatters/VectorType.h
index e69de29bb2d1..e69de29bb2d1 100644
--- a/tools/lldb-platform/exports
+++ b/include/lldb/DataFormatters/VectorType.h
diff --git a/include/lldb/Expression/ClangASTSource.h b/include/lldb/Expression/ClangASTSource.h
index 3e41a9e69e9b..46140d2f2e64 100644
--- a/include/lldb/Expression/ClangASTSource.h
+++ b/include/lldb/Expression/ClangASTSource.h
@@ -15,6 +15,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
#include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Target/Target.h"
#include "llvm/ADT/SmallSet.h"
@@ -45,39 +46,40 @@ public:
/// @param[in] declMap
/// A reference to the LLDB object that handles entity lookup.
//------------------------------------------------------------------
- ClangASTSource (const lldb::TargetSP &target) :
+ ClangASTSource (const lldb::TargetSP &target) :
m_import_in_progress (false),
m_lookups_enabled (false),
m_target (target),
m_ast_context (NULL),
+ m_active_lexical_decls (),
m_active_lookups ()
{
m_ast_importer = m_target->GetClangASTImporter();
}
-
+
//------------------------------------------------------------------
/// Destructor
//------------------------------------------------------------------
- ~ClangASTSource();
-
+ ~ClangASTSource();
+
//------------------------------------------------------------------
/// Interface stubs.
//------------------------------------------------------------------
- clang::Decl *GetExternalDecl (uint32_t) { return NULL; }
- clang::Stmt *GetExternalDeclStmt (uint64_t) { return NULL; }
- clang::Selector GetExternalSelector (uint32_t) { return clang::Selector(); }
- uint32_t GetNumExternalSelectors () { return 0; }
- clang::CXXBaseSpecifier *GetExternalCXXBaseSpecifiers (uint64_t Offset)
+ clang::Decl *GetExternalDecl (uint32_t) override { return NULL; }
+ clang::Stmt *GetExternalDeclStmt (uint64_t) override { return NULL; }
+ clang::Selector GetExternalSelector (uint32_t) override { return clang::Selector(); }
+ uint32_t GetNumExternalSelectors () override { return 0; }
+ clang::CXXBaseSpecifier *GetExternalCXXBaseSpecifiers (uint64_t Offset) override
{ return NULL; }
void MaterializeVisibleDecls (const clang::DeclContext *DC)
{ return; }
-
+
void InstallASTContext (clang::ASTContext *ast_context)
{
m_ast_context = ast_context;
m_ast_importer->InstallMapCompleter(ast_context, *this);
}
-
+
//
// APIs for ExternalASTSource
//
@@ -100,10 +102,8 @@ public:
/// @return
/// Whatever SetExternalVisibleDeclsForName returns.
//------------------------------------------------------------------
- bool
- FindExternalVisibleDeclsByName (const clang::DeclContext *DC,
- clang::DeclarationName Name);
-
+ bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC, clang::DeclarationName Name) override;
+
//------------------------------------------------------------------
/// Enumerate all Decls in a given lexical context.
///
@@ -117,11 +117,10 @@ public:
/// @param[in] Decls
/// A vector that is filled in with matching Decls.
//------------------------------------------------------------------
- clang::ExternalLoadResult
- FindExternalLexicalDecls (const clang::DeclContext *DC,
- bool (*isKindWeWant)(clang::Decl::Kind),
- llvm::SmallVectorImpl<clang::Decl*> &Decls);
-
+ clang::ExternalLoadResult FindExternalLexicalDecls(const clang::DeclContext *DC,
+ bool (*isKindWeWant)(clang::Decl::Kind),
+ llvm::SmallVectorImpl<clang::Decl *> &Decls) override;
+
//------------------------------------------------------------------
/// Specify the layout of the contents of a RecordDecl.
///
@@ -154,33 +153,28 @@ public:
///
/// @return
/// True <=> the layout is valid.
- //-----------------------------------------------------------------
- bool
- layoutRecordType(const clang::RecordDecl *Record,
- uint64_t &Size,
- uint64_t &Alignment,
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets);
-
+ //-----------------------------------------------------------------
+ bool layoutRecordType(const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets) override;
+
//------------------------------------------------------------------
/// Complete a TagDecl.
///
/// @param[in] Tag
/// The Decl to be completed in place.
//------------------------------------------------------------------
- virtual void
- CompleteType (clang::TagDecl *Tag);
-
+ void CompleteType(clang::TagDecl *Tag) override;
+
//------------------------------------------------------------------
/// Complete an ObjCInterfaceDecl.
///
/// @param[in] Class
/// The Decl to be completed in place.
//------------------------------------------------------------------
- virtual void
- CompleteType (clang::ObjCInterfaceDecl *Class);
-
+ void CompleteType(clang::ObjCInterfaceDecl *Class) override;
+
//------------------------------------------------------------------
/// Called on entering a translation unit. Tells Clang by calling
/// setHasExternalVisibleStorage() and setHasExternalLexicalStorage()
@@ -189,8 +183,8 @@ public:
/// @param[in] ASTConsumer
/// Unused.
//------------------------------------------------------------------
- void StartTranslationUnit (clang::ASTConsumer *Consumer);
-
+ void StartTranslationUnit(clang::ASTConsumer *Consumer) override;
+
//
// APIs for NamespaceMapCompleter
//
@@ -209,10 +203,9 @@ public:
/// The map for the namespace's parent namespace, if there is
/// one.
//------------------------------------------------------------------
- void CompleteNamespaceMap (ClangASTImporter::NamespaceMapSP &namespace_map,
- const ConstString &name,
- ClangASTImporter::NamespaceMapSP &parent_map) const;
-
+ void CompleteNamespaceMap(ClangASTImporter::NamespaceMapSP &namespace_map, const ConstString &name,
+ ClangASTImporter::NamespaceMapSP &parent_map) const override;
+
//
// Helper APIs
//
@@ -249,41 +242,37 @@ public:
m_original(original)
{
}
-
+
bool
- FindExternalVisibleDeclsByName (const clang::DeclContext *DC,
- clang::DeclarationName Name)
+ FindExternalVisibleDeclsByName(const clang::DeclContext *DC, clang::DeclarationName Name) override
{
return m_original.FindExternalVisibleDeclsByName(DC, Name);
}
-
- clang::ExternalLoadResult
- FindExternalLexicalDecls (const clang::DeclContext *DC,
- bool (*isKindWeWant)(clang::Decl::Kind),
- llvm::SmallVectorImpl<clang::Decl*> &Decls)
+
+ clang::ExternalLoadResult
+ FindExternalLexicalDecls(const clang::DeclContext *DC, bool (*isKindWeWant)(clang::Decl::Kind),
+ llvm::SmallVectorImpl<clang::Decl *> &Decls) override
{
return m_original.FindExternalLexicalDecls(DC, isKindWeWant, Decls);
}
-
+
void
- CompleteType (clang::TagDecl *Tag)
+ CompleteType(clang::TagDecl *Tag) override
{
return m_original.CompleteType(Tag);
}
-
- void
- CompleteType (clang::ObjCInterfaceDecl *Class)
+
+ void
+ CompleteType(clang::ObjCInterfaceDecl *Class) override
{
return m_original.CompleteType(Class);
}
-
- bool
- layoutRecordType(const clang::RecordDecl *Record,
- uint64_t &Size,
- uint64_t &Alignment,
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets)
+
+ bool
+ layoutRecordType(const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets) override
{
return m_original.layoutRecordType(Record,
Size,
@@ -293,7 +282,8 @@ public:
VirtualBaseOffsets);
}
- void StartTranslationUnit (clang::ASTConsumer *Consumer)
+ void
+ StartTranslationUnit(clang::ASTConsumer *Consumer) override
{
return m_original.StartTranslationUnit(Consumer);
}
@@ -413,8 +403,9 @@ protected:
bool m_lookups_enabled;
const lldb::TargetSP m_target; ///< The target to use in finding variables and types.
- clang::ASTContext *m_ast_context; ///< The AST context requests are coming in for.
+ clang::ASTContext *m_ast_context; ///< The AST context requests are coming in for.
ClangASTImporter *m_ast_importer; ///< The target's AST importer.
+ std::set<const clang::Decl *> m_active_lexical_decls;
std::set<const char *> m_active_lookups;
};
@@ -485,8 +476,12 @@ struct NameSearchContext {
///
/// @param[in] type
/// The opaque QualType for the FunDecl being registered.
+ ///
+ /// @param[in] extern_c
+ /// If true, build an extern "C" linkage specification for this.
//------------------------------------------------------------------
- clang::NamedDecl *AddFunDecl(const ClangASTType &type);
+ clang::NamedDecl *AddFunDecl(const ClangASTType &type,
+ bool extern_c = false);
//------------------------------------------------------------------
/// Create a FunDecl with the name being searched for and generic
@@ -513,7 +508,7 @@ struct NameSearchContext {
/// The DeclContextLookupResult, usually returned as the result
/// of querying a DeclContext.
//------------------------------------------------------------------
- void AddLookupResult (clang::DeclContextLookupConstResult result);
+ void AddLookupResult (clang::DeclContextLookupResult result);
//------------------------------------------------------------------
/// Add a NamedDecl to the list of results.
diff --git a/include/lldb/Expression/ClangExpressionDeclMap.h b/include/lldb/Expression/ClangExpressionDeclMap.h
index 8a4aa82b8727..f24500ab5237 100644
--- a/include/lldb/Expression/ClangExpressionDeclMap.h
+++ b/include/lldb/Expression/ClangExpressionDeclMap.h
@@ -100,6 +100,9 @@ public:
WillParse (ExecutionContext &exe_ctx,
Materializer *materializer);
+ void
+ InstallCodeGenerator (clang::ASTConsumer *code_gen);
+
//------------------------------------------------------------------
/// [Used by ClangExpressionParser] For each variable that had an unknown
/// type at the beginning of parsing, determine its final type now.
@@ -396,11 +399,6 @@ private:
{
public:
ParserVars(ClangExpressionDeclMap &decl_map) :
- m_exe_ctx(),
- m_sym_ctx(),
- m_persistent_vars(NULL),
- m_enable_lookups(false),
- m_materializer(NULL),
m_decl_map(decl_map)
{
}
@@ -415,12 +413,13 @@ private:
return NULL;
}
- ExecutionContext m_exe_ctx; ///< The execution context to use when parsing.
- SymbolContext m_sym_ctx; ///< The symbol context to use in finding variables and types.
- ClangPersistentVariables *m_persistent_vars; ///< The persistent variables for the process.
- bool m_enable_lookups; ///< Set to true during parsing if we have found the first "$__lldb" name.
- TargetInfo m_target_info; ///< Basic information about the target.
- Materializer *m_materializer; ///< If non-NULL, the materializer to use when reporting used variables.
+ ExecutionContext m_exe_ctx; ///< The execution context to use when parsing.
+ SymbolContext m_sym_ctx; ///< The symbol context to use in finding variables and types.
+ ClangPersistentVariables *m_persistent_vars = nullptr; ///< The persistent variables for the process.
+ bool m_enable_lookups = false; ///< Set to true during parsing if we have found the first "$__lldb" name.
+ TargetInfo m_target_info; ///< Basic information about the target.
+ Materializer *m_materializer = nullptr; ///< If non-NULL, the materializer to use when reporting used variables.
+ clang::ASTConsumer *m_code_gen = nullptr; ///< If non-NULL, a code generator that receives new top-level functions.
private:
ClangExpressionDeclMap &m_decl_map;
DISALLOW_COPY_AND_ASSIGN (ParserVars);
diff --git a/include/lldb/Expression/ClangExpressionParser.h b/include/lldb/Expression/ClangExpressionParser.h
index 0f578c55942e..21a27a489bcd 100644
--- a/include/lldb/Expression/ClangExpressionParser.h
+++ b/include/lldb/Expression/ClangExpressionParser.h
@@ -145,7 +145,6 @@ private:
std::unique_ptr<clang::CompilerInstance> m_compiler; ///< The Clang compiler used to parse expressions into IR
std::unique_ptr<clang::Builtin::Context> m_builtin_context; ///< Context for Clang built-ins
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
class LLDBPreprocessorCallbacks;
diff --git a/include/lldb/Expression/ClangFunction.h b/include/lldb/Expression/ClangFunction.h
index c122b21be279..cf7e2592021f 100644
--- a/include/lldb/Expression/ClangFunction.h
+++ b/include/lldb/Expression/ClangFunction.h
@@ -22,6 +22,7 @@
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectList.h"
#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Target/Process.h"
namespace lldb_private
@@ -412,7 +413,7 @@ private:
//------------------------------------------------------------------
// Note: the parser needs to be destructed before the execution unit, so
- // declare the the execution unit first.
+ // declare the execution unit first.
std::shared_ptr<IRExecutionUnit> m_execution_unit_sp;
std::unique_ptr<ClangExpressionParser> m_parser; ///< The parser responsible for compiling the function.
lldb::ModuleWP m_jit_module_wp;
diff --git a/include/lldb/Expression/ClangModulesDeclVendor.h b/include/lldb/Expression/ClangModulesDeclVendor.h
index a35b86a665ff..a8297c8fa331 100644
--- a/include/lldb/Expression/ClangModulesDeclVendor.h
+++ b/include/lldb/Expression/ClangModulesDeclVendor.h
@@ -15,6 +15,7 @@
#include "lldb/Symbol/DeclVendor.h"
#include "lldb/Target/Platform.h"
+#include <set>
#include <vector>
namespace lldb_private
@@ -34,6 +35,10 @@ public:
static ClangModulesDeclVendor *
Create(Target &target);
+ typedef std::vector<ConstString> ModulePath;
+ typedef uintptr_t ModuleID;
+ typedef std::vector<ModuleID> ModuleVector;
+
//------------------------------------------------------------------
/// Add a module to the list of modules to search.
///
@@ -41,6 +46,10 @@ public:
/// The path to the exact module to be loaded. E.g., if the desired
/// module is std.io, then this should be { "std", "io" }.
///
+ /// @param[in] exported_modules
+ /// If non-NULL, a pointer to a vector to populate with the ID of every
+ /// module that is re-exported by the specified module.
+ ///
/// @param[in] error_stream
/// A stream to populate with the output of the Clang parser when
/// it tries to load the module.
@@ -51,7 +60,69 @@ public:
/// load, then this will always return false for this ModuleImporter.
//------------------------------------------------------------------
virtual bool
- AddModule(std::vector<llvm::StringRef> &path, Stream &error_stream) = 0;
+ AddModule(ModulePath &path,
+ ModuleVector *exported_modules,
+ Stream &error_stream) = 0;
+
+ //------------------------------------------------------------------
+ /// Add all modules referred to in a given compilation unit to the list
+ /// of modules to search.
+ ///
+ /// @param[in] cu
+ /// The compilation unit to scan for imported modules.
+ ///
+ /// @param[in] exported_modules
+ /// A vector to populate with the ID of each module loaded (directly
+ /// and via re-exports) in this way.
+ ///
+ /// @param[in] error_stream
+ /// A stream to populate with the output of the Clang parser when
+ /// it tries to load the modules.
+ ///
+ /// @return
+ /// True if all modules referred to by the compilation unit could be
+ /// loaded; false if one could not be loaded. If the compiler
+ /// encountered a fatal error during a previous module
+ /// load, then this will always return false for this ModuleImporter.
+ //------------------------------------------------------------------
+ virtual bool
+ AddModulesForCompileUnit(CompileUnit &cu,
+ ModuleVector &exported_modules,
+ Stream &error_stream) = 0;
+
+ //------------------------------------------------------------------
+ /// Enumerate all the macros that are defined by a given set of modules
+ /// that are already imported.
+ ///
+ /// @param[in] modules
+ /// The unique IDs for all modules to query. Later modules have higher
+ /// priority, just as if you @imported them in that order. This matters
+ /// if module A #defines a macro and module B #undefs it.
+ ///
+ /// @param[in] handler
+ /// A function to call with the text of each #define (including the
+ /// #define directive). #undef directives are not included; we simply
+ /// elide any corresponding #define. If this function returns true,
+ /// we stop the iteration immediately.
+ //------------------------------------------------------------------
+ virtual void
+ ForEachMacro(const ModuleVector &modules,
+ std::function<bool (const std::string &)> handler) = 0;
+
+ //------------------------------------------------------------------
+ /// Query whether Clang supports modules for a particular language.
+ /// LLDB uses this to decide whether to try to find the modules loaded
+ /// by a gaiven compile unit.
+ ///
+ /// @param[in] language
+ /// The language to query for.
+ ///
+ /// @return
+ /// True if Clang has modules for the given language.
+ //------------------------------------------------------------------
+ static bool
+ LanguageSupportsClangModules (lldb::LanguageType language);
+
};
}
diff --git a/include/lldb/Expression/ClangPersistentVariables.h b/include/lldb/Expression/ClangPersistentVariables.h
index 6d9dae954734..247f87fae41b 100644
--- a/include/lldb/Expression/ClangPersistentVariables.h
+++ b/include/lldb/Expression/ClangPersistentVariables.h
@@ -11,6 +11,8 @@
#define liblldb_ClangPersistentVariables_h_
#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/ClangModulesDeclVendor.h"
+
#include "llvm/ADT/DenseMap.h"
namespace lldb_private
@@ -63,11 +65,25 @@ public:
clang::TypeDecl *
GetPersistentType (const ConstString &name);
+ void
+ AddHandLoadedClangModule(ClangModulesDeclVendor::ModuleID module)
+ {
+ m_hand_loaded_clang_modules.push_back(module);
+ }
+
+ const ClangModulesDeclVendor::ModuleVector &GetHandLoadedClangModules()
+ {
+ return m_hand_loaded_clang_modules;
+ }
+
private:
uint32_t m_next_persistent_variable_id; ///< The counter used by GetNextResultName().
typedef llvm::DenseMap<const char *, clang::TypeDecl *> PersistentTypeMap;
PersistentTypeMap m_persistent_types; ///< The persistent types declared by the user.
+
+ ClangModulesDeclVendor::ModuleVector m_hand_loaded_clang_modules; ///< These are Clang modules we hand-loaded; these are the highest-
+ ///< priority source for macros.
};
}
diff --git a/include/lldb/Expression/ClangUserExpression.h b/include/lldb/Expression/ClangUserExpression.h
index f51c9851789a..dbea48148e14 100644
--- a/include/lldb/Expression/ClangUserExpression.h
+++ b/include/lldb/Expression/ClangUserExpression.h
@@ -45,8 +45,7 @@ namespace lldb_private
class ClangUserExpression : public ClangExpression
{
public:
- typedef std::shared_ptr<ClangUserExpression> ClangUserExpressionSP;
-
+
enum { kDefaultTimeout = 500000u };
//------------------------------------------------------------------
/// Constructor
@@ -146,7 +145,7 @@ public:
Execute (Stream &error_stream,
ExecutionContext &exe_ctx,
const EvaluateExpressionOptions& options,
- ClangUserExpressionSP &shared_ptr_to_me,
+ lldb::ClangUserExpressionSP &shared_ptr_to_me,
lldb::ClangExpressionVariableSP &result);
//------------------------------------------------------------------
@@ -307,7 +306,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_objectivec based on the environment.
+ /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the environment.
//------------------------------------------------------------------
void
@@ -349,9 +348,9 @@ private:
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).
- bool m_static_method; ///< True if the expression is compiled as a static (or class) method (currently true if it was parsed when exe_ctx was in an Objective-C class method).
+ bool m_in_cplusplus_method; ///< 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_in_objectivec_method; ///< 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).
+ bool m_in_static_method; ///< True if the expression is compiled as a static (or class) method (currently true if it was parsed when exe_ctx was in an Objective-C class method).
bool m_needs_object_ptr; ///< True if "this" or "self" must be looked up and passed in. False if the expression doesn't really use them and they can be NULL.
bool m_const_object; ///< True if "this" is const.
Target *m_target; ///< The target for storing persistent data like types and variables.
diff --git a/include/lldb/Expression/IRForTarget.h b/include/lldb/Expression/IRForTarget.h
index 0ad34904f563..b81fab7a8a83 100644
--- a/include/lldb/Expression/IRForTarget.h
+++ b/include/lldb/Expression/IRForTarget.h
@@ -640,6 +640,9 @@ private:
return m_stream_string;
}
lldb::addr_t Allocate();
+
+ lldb::TargetSP
+ GetTarget();
private:
lldb_private::IRExecutionUnit &m_execution_unit;
lldb_private::StreamString m_stream_string;
diff --git a/include/lldb/Expression/IRMemoryMap.h b/include/lldb/Expression/IRMemoryMap.h
index 4faa5226d9b4..0da8384c8e63 100644
--- a/include/lldb/Expression/IRMemoryMap.h
+++ b/include/lldb/Expression/IRMemoryMap.h
@@ -69,14 +69,22 @@ public:
// This function can return NULL.
ExecutionContextScope *GetBestExecutionContextScope() const;
+ lldb::TargetSP
+ GetTarget ()
+ {
+ return m_target_wp.lock();
+ }
+
protected:
// This function should only be used if you know you are using the JIT.
// Any other cases should use GetBestExecutionContextScope().
- lldb::ProcessWP GetProcessWP ()
+
+ lldb::ProcessWP &
+ GetProcessWP ()
{
return m_process_wp;
}
-
+
private:
struct Allocation
{
diff --git a/include/lldb/Expression/IRToDWARF.h b/include/lldb/Expression/IRToDWARF.h
index 43dc99d6d476..a4ae9b7ebfae 100644
--- a/include/lldb/Expression/IRToDWARF.h
+++ b/include/lldb/Expression/IRToDWARF.h
@@ -11,7 +11,7 @@
#define liblldb_IRToDWARF_h_
#include "llvm/Pass.h"
-#include "llvm/PassManager.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "lldb/lldb-public.h"
diff --git a/include/lldb/Host/Editline.h b/include/lldb/Host/Editline.h
index 9fce193efc9f..697be4cd8e77 100644
--- a/include/lldb/Host/Editline.h
+++ b/include/lldb/Host/Editline.h
@@ -171,17 +171,13 @@ namespace lldb_private {
uint32_t
GetCurrentLine();
- /// Hides the current input session in preparation for output
- void
- Hide();
-
- /// Prepare to return to editing after a call to Hide()
- void
- Refresh();
-
/// Interrupt the current edit as if ^C was pressed
bool
Interrupt();
+
+ /// Cancel this edit and oblitarate all trace of it
+ bool
+ Cancel();
/// Register a callback for the tab key
void
@@ -207,6 +203,9 @@ namespace lldb_private {
bool
GetLines (int first_line_number, StringList &lines, bool &interrupted);
+ void
+ PrintAsync (Stream *stream, const char *s, size_t len);
+
private:
/// Sets the lowest line number for multi-line editing sessions. A value of zero suppresses
@@ -335,7 +334,6 @@ namespace lldb_private {
bool m_multiline_enabled = false;
std::vector<EditLineStringType> m_input_lines;
EditorStatus m_editor_status;
- bool m_editor_getting_char = false;
bool m_color_prompts = true;
int m_terminal_width = 0;
int m_base_line_number = 0;
@@ -359,6 +357,8 @@ namespace lldb_private {
const char * m_fix_indentation_callback_chars = nullptr;
CompleteCallbackType m_completion_callback = nullptr;
void * m_completion_callback_baton = nullptr;
+
+ Mutex m_output_mutex;
};
}
diff --git a/include/lldb/Host/File.h b/include/lldb/Host/File.h
index 8219cc06fdc2..5747cb5adcfd 100644
--- a/include/lldb/Host/File.h
+++ b/include/lldb/Host/File.h
@@ -470,7 +470,7 @@ public:
GetPermissions(Error &error) const;
static uint32_t
- GetPermissions (const char *path, Error &error);
+ GetPermissions(const FileSpec &file_spec, Error &error);
//------------------------------------------------------------------
diff --git a/include/lldb/Host/FileSpec.h b/include/lldb/Host/FileSpec.h
index 173d948e687b..d0338d41db1b 100644
--- a/include/lldb/Host/FileSpec.h
+++ b/include/lldb/Host/FileSpec.h
@@ -11,6 +11,8 @@
#define liblldb_FileSpec_h_
#if defined(__cplusplus)
+#include <functional>
+
#include "lldb/lldb-private.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/STLUtils.h"
@@ -78,6 +80,12 @@ public:
//------------------------------------------------------------------
explicit FileSpec (const char *path, bool resolve_path, PathSyntax syntax = ePathSyntaxHostNative);
+ explicit FileSpec (const char *path, bool resolve_path, ArchSpec arch);
+
+ explicit FileSpec(const std::string &path, bool resolve_path, PathSyntax syntax = ePathSyntaxHostNative);
+
+ explicit FileSpec(const std::string &path, bool resolve_path, ArchSpec arch);
+
//------------------------------------------------------------------
/// Copy constructor
///
@@ -259,7 +267,7 @@ public:
/// The stream to which to dump the object description.
//------------------------------------------------------------------
void
- Dump (Stream *s) const;
+ Dump(Stream *s) const;
//------------------------------------------------------------------
/// Existence test.
@@ -359,16 +367,25 @@ public:
IsSourceImplementationFile () const;
//------------------------------------------------------------------
- /// Returns true if the filespec represents path that is relative
- /// path to the current working directory.
+ /// Returns true if the filespec represents a relative path.
///
/// @return
- /// \b true if the filespec represents a current working
- /// directory relative path, \b false otherwise.
+ /// \b true if the filespec represents a relative path,
+ /// \b false otherwise.
//------------------------------------------------------------------
bool
- IsRelativeToCurrentWorkingDirectory () const;
-
+ IsRelative() const;
+
+ //------------------------------------------------------------------
+ /// Returns true if the filespec represents an absolute path.
+ ///
+ /// @return
+ /// \b true if the filespec represents an absolute path,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsAbsolute() const;
+
TimeValue
GetModificationTime () const;
@@ -408,6 +425,20 @@ public:
std::string
GetPath (bool denormalize = true) const;
+ const char *
+ GetCString(bool denormalize = true) const;
+
+ //------------------------------------------------------------------
+ /// Extract the full path to the file.
+ ///
+ /// Extract the directory and path into an llvm::SmallVectorImpl<>
+ ///
+ /// @return
+ /// Returns a std::string with the directory and filename
+ /// concatenated.
+ //------------------------------------------------------------------
+ void GetPath(llvm::SmallVectorImpl<char> &path, bool denormalize = true) const;
+
//------------------------------------------------------------------
/// Extract the extension of the file.
///
@@ -530,6 +561,45 @@ public:
lldb::DataBufferSP
MemoryMapFileContents (off_t offset = 0, size_t length = SIZE_MAX) const;
+
+ //------------------------------------------------------------------
+ /// Memory map part of, or the entire contents of, a file only if
+ /// the file is local (not on a network mount).
+ ///
+ /// Returns a shared pointer to a data buffer that contains all or
+ /// part of the contents of a file. The data will be memory mapped
+ /// if the file is local and will lazily page in data from the file
+ /// as memory is accessed. If the data is memory mapped, 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
+ /// truncated. The final number of bytes that get mapped can be
+ /// verified using the DataBuffer::GetByteSize() function on the return
+ /// shared data pointer object contents.
+ ///
+ /// If the file is on a network mount the data will be read into a
+ /// heap buffer immediately so that accesses to the data won't later
+ /// cause a crash if we touch a page that isn't paged in and the
+ /// network mount has been disconnected or gone away.
+ ///
+ /// @param[in] offset
+ /// The offset in bytes from the beginning of the file where
+ /// memory mapping should begin.
+ ///
+ /// @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.
+ ///
+ /// @return
+ /// 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.
+ //------------------------------------------------------------------
+ lldb::DataBufferSP
+ MemoryMapFileContentsIfLocal(off_t file_offset, size_t file_size) const;
+
//------------------------------------------------------------------
/// Read part of, or the entire contents of, a file into a heap based data buffer.
///
@@ -579,9 +649,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);
-
+ //------------------------------------------------------------------
+ /// Normalize a pathname by collapsing redundant separators and
+ /// up-level references.
+ //------------------------------------------------------------------
+ void
+ NormalizePath ();
//------------------------------------------------------------------
/// Run through the input string, replaying the effect of any ".." and produce
@@ -613,6 +686,15 @@ public:
void
SetFile (const char *path, bool resolve_path, PathSyntax syntax = ePathSyntaxHostNative);
+ void
+ SetFile(const char *path, bool resolve_path, ArchSpec arch);
+
+ void
+ SetFile(const std::string &path, bool resolve_path, PathSyntax syntax = ePathSyntaxHostNative);
+
+ void
+ SetFile(const std::string &path, bool resolve_path, ArchSpec arch);
+
bool
IsResolved () const
{
@@ -668,10 +750,25 @@ public:
FileSpec
CopyByRemovingLastPathComponent () const;
-
+
void
- AppendPathComponent (const char *new_path);
-
+ PrependPathComponent(const char *new_path);
+
+ void
+ PrependPathComponent(const std::string &new_path);
+
+ void
+ PrependPathComponent(const FileSpec &new_path);
+
+ void
+ AppendPathComponent(const char *new_path);
+
+ void
+ AppendPathComponent(const std::string &new_path);
+
+ void
+ AppendPathComponent(const FileSpec &new_path);
+
void
RemoveLastPathComponent ();
@@ -706,8 +803,7 @@ public:
typedef EnumerateDirectoryResult (*EnumerateDirectoryCallbackType) (void *baton,
FileType file_type,
- const FileSpec &spec
-);
+ const FileSpec &spec);
static EnumerateDirectoryResult
EnumerateDirectory (const char *dir_path,
@@ -717,6 +813,11 @@ public:
EnumerateDirectoryCallbackType callback,
void *callback_baton);
+ typedef std::function <EnumerateDirectoryResult(FileType file_type, const FileSpec &spec)> DirectoryCallback;
+
+ static EnumerateDirectoryResult
+ ForEachItemInDirectory (const char *dir_path, DirectoryCallback const &callback);
+
protected:
//------------------------------------------------------------------
// Member variables
diff --git a/include/lldb/Host/FileSystem.h b/include/lldb/Host/FileSystem.h
index adcbfc9d590d..bea1ec80172e 100644
--- a/include/lldb/Host/FileSystem.h
+++ b/include/lldb/Host/FileSystem.h
@@ -24,19 +24,36 @@ 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 MakeDirectory(const FileSpec &file_spec, uint32_t mode);
+ static Error DeleteDirectory(const FileSpec &file_spec, bool recurse);
- static Error GetFilePermissions(const char *path, uint32_t &file_permissions);
- static Error SetFilePermissions(const char *path, uint32_t file_permissions);
+ static Error GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions);
+ static Error SetFilePermissions(const FileSpec &file_spec,
+ 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 Error Hardlink(const FileSpec &src, const FileSpec &dst);
+ static Error Symlink(const FileSpec &src, const FileSpec &dst);
+ static Error Readlink(const FileSpec &src, FileSpec &dst);
+ static Error Unlink(const FileSpec &file_spec);
static bool CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high);
+ static bool CalculateMD5(const FileSpec &file_spec,
+ uint64_t offset,
+ uint64_t length,
+ uint64_t &low,
+ uint64_t &high);
+
+ static bool CalculateMD5AsString(const FileSpec &file_spec, std::string& digest_str);
+ static bool CalculateMD5AsString(const FileSpec &file_spec,
+ uint64_t offset,
+ uint64_t length,
+ std::string& digest_str);
+
+ /// Return \b true if \a spec is on a locally mounted file system, \b false otherwise.
+ static bool IsLocal(const FileSpec &spec);
};
}
diff --git a/include/lldb/Host/Host.h b/include/lldb/Host/Host.h
index 9a68c698c826..caf33634057d 100644
--- a/include/lldb/Host/Host.h
+++ b/include/lldb/Host/Host.h
@@ -133,9 +133,6 @@ public:
static const char *
GetSignalAsCString (int signo);
- static void
- WillTerminate ();
-
typedef void (*ThreadLocalStorageCleanupCallback) (void *p);
static lldb::thread_key_t
@@ -236,12 +233,16 @@ public:
GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info);
#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined (__NetBSD__)
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
+
static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info);
static Error LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid);
static bool AddPosixSpawnFileAction(void *file_actions, const FileAction *info, Log *log, Error &error);
-#endif
+
+#endif // !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
+#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__)
static const lldb_private::UnixSignalsSP&
GetUnixSignals ();
@@ -249,14 +250,33 @@ public:
static Error
LaunchProcess (ProcessLaunchInfo &launch_info);
+ //------------------------------------------------------------------
+ /// Perform expansion of the command-line for this launch info
+ /// This can potentially involve wildcard expansion
+ // environment variable replacement, and whatever other
+ // argument magic the platform defines as part of its typical
+ // user experience
+ //------------------------------------------------------------------
+ static Error
+ ShellExpandArguments (ProcessLaunchInfo &launch_info);
+
+ static Error
+ RunShellCommand(const char *command, // Shouldn't be NULL
+ const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec,
+ bool run_in_default_shell = true);
+
static Error
- RunShellCommand (const char *command, // Shouldn't be NULL
- const char *working_dir, // Pass NULL to use the current working directory
- int *status_ptr, // Pass NULL if you don't want the process exit status
- int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
- std::string *command_output, // Pass NULL if you don't want the command output
- uint32_t timeout_sec,
- bool run_in_default_shell = true);
+ RunShellCommand(const Args& args,
+ const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec,
+ bool run_in_default_shell = true);
static lldb::DataBufferSP
GetAuxvData (lldb_private::Process *process);
@@ -268,9 +288,6 @@ public:
OpenFileInExternalEditor (const FileSpec &file_spec,
uint32_t line_no);
- static void
- Backtrace (Stream &strm, uint32_t max_frames);
-
static size_t
GetEnvironment (StringList &env);
};
diff --git a/include/lldb/Host/HostInfo.h b/include/lldb/Host/HostInfo.h
index cbbf6cd2d49c..6bb009997896 100644
--- a/include/lldb/Host/HostInfo.h
+++ b/include/lldb/Host/HostInfo.h
@@ -38,8 +38,13 @@
#include "lldb/Host/windows/HostInfoWindows.h"
#define HOST_INFO_TYPE HostInfoWindows
#elif defined(__linux__)
+#if defined(__ANDROID_NDK__)
+#include "lldb/Host/android/HostInfoAndroid.h"
+#define HOST_INFO_TYPE HostInfoAndroid
+#else
#include "lldb/Host/linux/HostInfoLinux.h"
#define HOST_INFO_TYPE HostInfoLinux
+#endif
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include "lldb/Host/freebsd/HostInfoFreeBSD.h"
#define HOST_INFO_TYPE HostInfoFreeBSD
diff --git a/include/lldb/Host/HostInfoBase.h b/include/lldb/Host/HostInfoBase.h
index 5a8a06329500..6a5f784ebba3 100644
--- a/include/lldb/Host/HostInfoBase.h
+++ b/include/lldb/Host/HostInfoBase.h
@@ -115,7 +115,9 @@ class HostInfoBase
protected:
static bool ComputeSharedLibraryDirectory(FileSpec &file_spec);
static bool ComputeSupportExeDirectory(FileSpec &file_spec);
- static bool ComputeTempFileDirectory(FileSpec &file_spec);
+ static bool ComputeProcessTempFileDirectory(FileSpec &file_spec);
+ static bool ComputeGlobalTempFileDirectory(FileSpec &file_spec);
+ static bool ComputeTempFileBaseDirectory(FileSpec &file_spec);
static bool ComputeHeaderDirectory(FileSpec &file_spec);
static bool ComputeSystemPluginsDirectory(FileSpec &file_spec);
static bool ComputeClangDirectory(FileSpec &file_spec);
diff --git a/include/lldb/Host/LockFile.h b/include/lldb/Host/LockFile.h
new file mode 100644
index 000000000000..a89560481874
--- /dev/null
+++ b/include/lldb/Host/LockFile.h
@@ -0,0 +1,27 @@
+//===-- LockFile.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_LockFile_h_
+#define liblldb_Host_LockFile_h_
+
+#if defined(_WIN32)
+#include "lldb/Host/windows/LockFileWindows.h"
+namespace lldb_private
+{
+typedef LockFileWindows LockFile;
+}
+#else
+#include "lldb/Host/posix/LockFilePosix.h"
+namespace lldb_private
+{
+typedef LockFilePosix LockFile;
+}
+#endif
+
+#endif // liblldb_Host_LockFile_h_
diff --git a/include/lldb/Host/LockFileBase.h b/include/lldb/Host/LockFileBase.h
new file mode 100644
index 000000000000..35dd7d817c59
--- /dev/null
+++ b/include/lldb/Host/LockFileBase.h
@@ -0,0 +1,73 @@
+//===-- LockFileBase.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_LockFileBase_h_
+#define liblldb_Host_LockFileBase_h_
+
+#include "lldb/Core/Error.h"
+
+#include <functional>
+
+namespace lldb_private
+{
+
+class LockFileBase
+{
+public:
+ virtual ~LockFileBase () = default;
+
+ bool
+ IsLocked () const;
+
+ Error
+ WriteLock (const uint64_t start, const uint64_t len);
+ Error
+ TryWriteLock (const uint64_t start, const uint64_t len);
+
+ Error
+ ReadLock (const uint64_t start, const uint64_t len);
+ Error
+ TryReadLock (const uint64_t start, const uint64_t len);
+
+ Error
+ Unlock ();
+
+protected:
+ using Locker = std::function<Error (const uint64_t, const uint64_t)>;
+
+ LockFileBase (int fd);
+
+ virtual bool
+ IsValidFile () const;
+
+ virtual Error
+ DoWriteLock (const uint64_t start, const uint64_t len) = 0;
+ virtual Error
+ DoTryWriteLock (const uint64_t start, const uint64_t len) = 0;
+
+ virtual Error
+ DoReadLock (const uint64_t start, const uint64_t len) = 0;
+ virtual Error
+ DoTryReadLock (const uint64_t start, const uint64_t len) = 0;
+
+ virtual Error
+ DoUnlock () = 0;
+
+ Error
+ DoLock (const Locker &locker, const uint64_t start, const uint64_t len);
+
+ int m_fd; // not owned.
+ bool m_locked;
+ uint64_t m_start;
+ uint64_t m_len;
+};
+
+}
+
+#endif
diff --git a/include/lldb/Host/PipeBase.h b/include/lldb/Host/PipeBase.h
index 5ef2bb530281..8680a252d8b6 100644
--- a/include/lldb/Host/PipeBase.h
+++ b/include/lldb/Host/PipeBase.h
@@ -40,6 +40,8 @@ class PipeBase
virtual int GetWriteFileDescriptor() const = 0;
virtual int ReleaseReadFileDescriptor() = 0;
virtual int ReleaseWriteFileDescriptor() = 0;
+ virtual void CloseReadFileDescriptor() = 0;
+ virtual void CloseWriteFileDescriptor() = 0;
// Close both descriptors
virtual void Close() = 0;
diff --git a/include/lldb/Host/Socket.h b/include/lldb/Host/Socket.h
index ee85f85fcaf2..f4599b5ab87b 100644
--- a/include/lldb/Host/Socket.h
+++ b/include/lldb/Host/Socket.h
@@ -56,7 +56,12 @@ public:
// 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, bool child_processes_inherit, Socket *&socket, Predicate<uint16_t>* predicate);
+ static Error TcpListen(
+ llvm::StringRef host_and_port,
+ bool child_processes_inherit,
+ Socket *&socket,
+ Predicate<uint16_t>* predicate,
+ int backlog = 5);
static Error TcpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket);
static Error UdpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket);
static Error UnixDomainConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket);
diff --git a/include/lldb/Host/Time.h b/include/lldb/Host/Time.h
new file mode 100644
index 000000000000..1481d381053d
--- /dev/null
+++ b/include/lldb/Host/Time.h
@@ -0,0 +1,26 @@
+//===-- Time.h --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Include system time headers, adding missing functions as necessary
+
+#ifndef liblldb_Host_Time_h_
+#define liblldb_Host_Time_h_
+
+#ifdef __ANDROID_NDK__
+#include <android/api-level.h>
+#endif
+
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+#include <time64.h>
+extern time_t timegm(struct tm* t);
+#else
+#include <time.h>
+#endif
+
+#endif // liblldb_Host_Time_h_
diff --git a/include/lldb/Host/XML.h b/include/lldb/Host/XML.h
new file mode 100644
index 000000000000..e3547d834635
--- /dev/null
+++ b/include/lldb/Host/XML.h
@@ -0,0 +1,234 @@
+//===-- XML.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_XML_h_
+#define liblldb_XML_h_
+
+// C Includes
+
+#if defined( LIBXML2_DEFINED )
+#include <libxml/xmlreader.h>
+#endif
+
+// C++ Includes
+
+#include <functional>
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "llvm/ADT/StringRef.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StructuredData.h"
+
+
+namespace lldb_private {
+
+#if defined( LIBXML2_DEFINED )
+ typedef xmlNodePtr XMLNodeImpl;
+ typedef xmlDocPtr XMLDocumentImpl;
+#else
+ typedef void * XMLNodeImpl;
+ typedef void * XMLDocumentImpl;
+#endif
+
+ class XMLNode;
+
+ typedef std::vector<std::string> NamePath;
+ typedef std::function <bool(const XMLNode &node)> NodeCallback;
+ typedef std::function <bool(const llvm::StringRef &name, const llvm::StringRef &value)> AttributeCallback;
+
+ class XMLNode
+ {
+ public:
+ XMLNode();
+
+ XMLNode(XMLNodeImpl node);
+
+ ~XMLNode();
+
+ explicit operator bool() const
+ {
+ return IsValid();
+ }
+
+ void
+ Clear();
+
+ bool
+ IsValid() const;
+
+ bool
+ IsElement () const;
+
+ llvm::StringRef
+ GetName() const;
+
+ bool
+ GetElementText (std::string &text) const;
+
+ bool
+ GetElementTextAsUnsigned (uint64_t &value, uint64_t fail_value = 0, int base = 0) const;
+
+ bool
+ GetElementTextAsFloat (double &value, double fail_value = 0.0) const;
+
+ bool
+ NameIs (const char *name) const;
+
+ XMLNode
+ GetParent() const;
+
+ XMLNode
+ GetSibling() const;
+
+ XMLNode
+ GetChild () const;
+
+ llvm::StringRef
+ GetAttributeValue(const char *name, const char *fail_value = NULL) const;
+
+ XMLNode
+ FindFirstChildElementWithName (const char *name) const;
+
+ XMLNode
+ GetElementForPath (const NamePath &path);
+
+ //----------------------------------------------------------------------
+ // Iterate through all sibling nodes of any type
+ //----------------------------------------------------------------------
+ void
+ ForEachSiblingNode (NodeCallback const &callback) const;
+
+ //----------------------------------------------------------------------
+ // Iterate through only the sibling nodes that are elements
+ //----------------------------------------------------------------------
+ void
+ ForEachSiblingElement (NodeCallback const &callback) const;
+
+ //----------------------------------------------------------------------
+ // Iterate through only the sibling nodes that are elements and whose
+ // name matches \a name.
+ //----------------------------------------------------------------------
+ void
+ ForEachSiblingElementWithName (const char *name, NodeCallback const &callback) const;
+
+ void
+ ForEachChildNode (NodeCallback const &callback) const;
+
+ void
+ ForEachChildElement (NodeCallback const &callback) const;
+
+ void
+ ForEachChildElementWithName (const char *name, NodeCallback const &callback) const;
+
+ void
+ ForEachAttribute (AttributeCallback const &callback) const;
+
+ protected:
+ XMLNodeImpl m_node;
+ };
+
+ class XMLDocument
+ {
+ public:
+
+ XMLDocument ();
+
+ ~XMLDocument ();
+
+ explicit operator bool() const
+ {
+ return IsValid();
+ }
+
+ bool
+ IsValid() const;
+
+ void
+ Clear();
+
+ bool
+ ParseFile (const char *path);
+
+ bool
+ ParseMemory (const char *xml, size_t xml_length, const char *url = "untitled.xml");
+
+ //----------------------------------------------------------------------
+ // If \a name is NULL, just get the root element node, else only return
+ // a value XMLNode if the name of the root element matches \a name.
+ //----------------------------------------------------------------------
+ XMLNode
+ GetRootElement(const char *required_name = nullptr);
+
+ const std::string &
+ GetErrors() const;
+
+ static void
+ ErrorCallback (void *ctx, const char *format, ...);
+
+ static bool
+ XMLEnabled ();
+
+ protected:
+ XMLDocumentImpl m_document;
+ StreamString m_errors;
+ };
+
+ class ApplePropertyList
+ {
+ public:
+ ApplePropertyList();
+
+ ApplePropertyList(const char *path);
+
+ ~ApplePropertyList();
+
+ bool
+ ParseFile (const char *path);
+
+ const std::string &
+ GetErrors() const;
+
+ explicit operator bool() const
+ {
+ return IsValid();
+ }
+
+ bool
+ IsValid() const;
+
+ XMLNode
+ GetValueNode (const char *key) const;
+
+ bool
+ GetValueAsString (const char *key, std::string &value) const;
+
+ StructuredData::ObjectSP
+ GetStructuredData();
+
+ protected:
+
+ // Using a node returned from GetValueNode() extract its value as a
+ // string (if possible). Array and dictionary nodes will return false
+ // as they have no string value. Boolean nodes will return true and
+ // \a value will be "true" or "false" as the string value comes from
+ // the element name itself. All other nodes will return the text
+ // content of the XMLNode.
+ static bool
+ ExtractStringFromValueNode (const XMLNode &node, std::string &value);
+
+ XMLDocument m_xml_doc;
+ XMLNode m_dict_node;
+ };
+} // namespace lldb_private
+
+#endif // liblldb_XML_h_
diff --git a/include/lldb/Host/common/NativeBreakpointList.h b/include/lldb/Host/common/NativeBreakpointList.h
index 51617330d075..aba2f8a74cdc 100644
--- a/include/lldb/Host/common/NativeBreakpointList.h
+++ b/include/lldb/Host/common/NativeBreakpointList.h
@@ -42,6 +42,9 @@ namespace lldb_private
Error
GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp);
+ Error
+ RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf, size_t size) const;
+
private:
typedef std::map<lldb::addr_t, NativeBreakpointSP> BreakpointMap;
diff --git a/include/lldb/Host/common/NativeProcessProtocol.h b/include/lldb/Host/common/NativeProcessProtocol.h
index 83c14a5ab37a..f6a685aae147 100644
--- a/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/include/lldb/Host/common/NativeProcessProtocol.h
@@ -16,6 +16,7 @@
#include "lldb/lldb-types.h"
#include "lldb/Core/Error.h"
#include "lldb/Host/Mutex.h"
+#include "llvm/ADT/StringRef.h"
#include "NativeBreakpointList.h"
#include "NativeWatchpointList.h"
@@ -90,13 +91,16 @@ namespace lldb_private
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;
+ ReadMemory(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) = 0;
virtual Error
- WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) = 0;
+ ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) = 0;
virtual Error
- AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) = 0;
+ WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) = 0;
+
+ virtual Error
+ AllocateMemory(size_t size, uint32_t permissions, lldb::addr_t &addr) = 0;
virtual Error
DeallocateMemory (lldb::addr_t addr) = 0;
@@ -283,6 +287,16 @@ namespace lldb_private
bool
UnregisterNativeDelegate (NativeDelegate &native_delegate);
+ // Called before termination of NativeProcessProtocol's instance.
+ virtual void
+ Terminate ();
+
+ virtual Error
+ GetLoadedModuleFileSpec(const char* module_path, FileSpec& file_spec) = 0;
+
+ virtual Error
+ GetFileLoadAddress(const llvm::StringRef& file_name, lldb::addr_t& load_addr) = 0;
+
protected:
lldb::pid_t m_pid;
diff --git a/include/lldb/Host/common/NativeRegisterContext.h b/include/lldb/Host/common/NativeRegisterContext.h
index e9c03e3c20a4..098f148f95d0 100644
--- a/include/lldb/Host/common/NativeRegisterContext.h
+++ b/include/lldb/Host/common/NativeRegisterContext.h
@@ -99,14 +99,26 @@ public:
virtual Error
ClearAllHardwareWatchpoints ();
+ virtual Error
+ IsWatchpointHit(uint32_t wp_index, bool &is_hit);
+
+ virtual Error
+ GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr);
+
+ virtual Error
+ IsWatchpointVacant (uint32_t wp_index, bool &is_vacant);
+
+ virtual lldb::addr_t
+ GetWatchpointAddress (uint32_t wp_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);
+ ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, size_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);
+ WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, size_t dst_len, const RegisterValue &reg_value);
//------------------------------------------------------------------
// Subclasses should not override these
@@ -129,6 +141,9 @@ public:
lldb::addr_t
GetPC (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+ virtual lldb::addr_t
+ GetPCfromBreakpointLocation (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
Error
SetPC (lldb::addr_t pc);
diff --git a/include/lldb/Host/common/SoftwareBreakpoint.h b/include/lldb/Host/common/SoftwareBreakpoint.h
index 1fed19eca612..83b3d18aa768 100644
--- a/include/lldb/Host/common/SoftwareBreakpoint.h
+++ b/include/lldb/Host/common/SoftwareBreakpoint.h
@@ -17,6 +17,8 @@ namespace lldb_private
{
class SoftwareBreakpoint : public NativeBreakpoint
{
+ friend class NativeBreakpointList;
+
public:
static Error
CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_spn);
diff --git a/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h b/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h
index 660b9d169bfc..bcbb6014b116 100644
--- a/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h
+++ b/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h
@@ -38,23 +38,25 @@ class ConnectionFileDescriptor : public Connection
ConnectionFileDescriptor(int fd, bool owns_fd);
+ ConnectionFileDescriptor(Socket* socket);
+
virtual ~ConnectionFileDescriptor();
- virtual bool IsConnected() const;
+ bool IsConnected() const override;
- virtual lldb::ConnectionStatus Connect(const char *s, Error *error_ptr);
+ lldb::ConnectionStatus Connect(const char *s, Error *error_ptr) override;
- virtual lldb::ConnectionStatus Disconnect(Error *error_ptr);
+ lldb::ConnectionStatus Disconnect(Error *error_ptr) override;
- virtual size_t Read(void *dst, size_t dst_len, uint32_t timeout_usec, lldb::ConnectionStatus &status, Error *error_ptr);
+ size_t Read(void *dst, size_t dst_len, uint32_t timeout_usec, lldb::ConnectionStatus &status, Error *error_ptr) override;
- virtual size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status, Error *error_ptr);
+ size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status, Error *error_ptr) override;
- virtual std::string GetURI();
+ std::string GetURI() override;
lldb::ConnectionStatus BytesAvailable(uint32_t timeout_usec, Error *error_ptr);
- bool InterruptRead();
+ bool InterruptRead() override;
lldb::IOObjectSP
GetReadObject()
@@ -104,6 +106,8 @@ class ConnectionFileDescriptor : public Connection
std::string m_uri;
private:
+ void InitializeSocket(Socket* socket);
+
DISALLOW_COPY_AND_ASSIGN(ConnectionFileDescriptor);
};
diff --git a/include/lldb/Host/posix/Fcntl.h b/include/lldb/Host/posix/Fcntl.h
new file mode 100644
index 000000000000..3e3a472f0a20
--- /dev/null
+++ b/include/lldb/Host/posix/Fcntl.h
@@ -0,0 +1,25 @@
+//===-- Fcntl.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This file defines fcntl functions & structures
+
+#ifndef liblldb_Host_posix_Fcntl_h_
+#define liblldb_Host_posix_Fcntl_h_
+
+#ifdef __ANDROID_NDK__
+#include <android/api-level.h>
+#endif
+
+#include <fcntl.h>
+
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6)
+#endif
+
+#endif // liblldb_Host_posix_Fcntl_h_
diff --git a/include/lldb/Host/posix/HostProcessPosix.h b/include/lldb/Host/posix/HostProcessPosix.h
index 8c1b0599e114..c9534991361b 100644
--- a/include/lldb/Host/posix/HostProcessPosix.h
+++ b/include/lldb/Host/posix/HostProcessPosix.h
@@ -29,13 +29,13 @@ class HostProcessPosix : public HostNativeProcessBase
virtual Error Signal(int signo) const;
static Error Signal(lldb::process_t process, int signo);
- virtual Error Terminate();
- virtual Error GetMainModule(FileSpec &file_spec) const;
+ Error Terminate() override;
+ Error GetMainModule(FileSpec &file_spec) const override;
- virtual lldb::pid_t GetProcessId() const;
- virtual bool IsRunning() const;
+ lldb::pid_t GetProcessId() const override;
+ bool IsRunning() const override;
- virtual HostThread StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals);
+ HostThread StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals) override;
};
}
diff --git a/include/lldb/Host/posix/HostThreadPosix.h b/include/lldb/Host/posix/HostThreadPosix.h
index e0eaedf73be2..8839b8d4068b 100644
--- a/include/lldb/Host/posix/HostThreadPosix.h
+++ b/include/lldb/Host/posix/HostThreadPosix.h
@@ -24,8 +24,8 @@ class HostThreadPosix : public HostNativeThreadBase
HostThreadPosix(lldb::thread_t thread);
virtual ~HostThreadPosix();
- virtual Error Join(lldb::thread_result_t *result);
- virtual Error Cancel();
+ Error Join(lldb::thread_result_t *result) override;
+ Error Cancel() override;
Error Detach();
};
diff --git a/include/lldb/Host/posix/LockFilePosix.h b/include/lldb/Host/posix/LockFilePosix.h
new file mode 100644
index 000000000000..999397ec2bb5
--- /dev/null
+++ b/include/lldb/Host/posix/LockFilePosix.h
@@ -0,0 +1,42 @@
+//===-- LockFilePosix.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_posix_LockFilePosix_h_
+#define liblldb_Host_posix_LockFilePosix_h_
+
+#include "lldb/Host/LockFileBase.h"
+
+namespace lldb_private {
+
+class LockFilePosix : public LockFileBase
+{
+public:
+ explicit LockFilePosix (int fd);
+ ~LockFilePosix ();
+
+protected:
+ Error
+ DoWriteLock (const uint64_t start, const uint64_t len) override;
+
+ Error
+ DoTryWriteLock (const uint64_t start, const uint64_t len) override;
+
+ Error
+ DoReadLock (const uint64_t start, const uint64_t len) override;
+
+ Error
+ DoTryReadLock (const uint64_t start, const uint64_t len) override;
+
+ Error
+ DoUnlock () override;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Host_posix_LockFilePosix_h_
diff --git a/include/lldb/Host/posix/PipePosix.h b/include/lldb/Host/posix/PipePosix.h
index fbdac66149d6..710b77d34bdc 100644
--- a/include/lldb/Host/posix/PipePosix.h
+++ b/include/lldb/Host/posix/PipePosix.h
@@ -16,7 +16,7 @@
namespace lldb_private {
//----------------------------------------------------------------------
-/// @class PipePosix PipePosix .h "lldb/Host/posix/PipePosix.h"
+/// @class PipePosix PipePosix.h "lldb/Host/posix/PipePosix.h"
/// @brief A posix-based implementation of Pipe, a class that abtracts
/// unix style pipes.
///
@@ -28,6 +28,11 @@ public:
static int kInvalidDescriptor;
PipePosix();
+ PipePosix(int read_fd, int write_fd);
+ PipePosix(const PipePosix &) = delete;
+ PipePosix(PipePosix &&pipe_posix);
+ PipePosix &operator=(const PipePosix &) = delete;
+ PipePosix &operator=(PipePosix &&pipe_posix);
~PipePosix() override;
@@ -55,6 +60,11 @@ public:
ReleaseReadFileDescriptor() override;
int
ReleaseWriteFileDescriptor() override;
+ void
+ CloseReadFileDescriptor() override;
+ void
+ CloseWriteFileDescriptor() override;
+
// Close both descriptors
void
@@ -69,11 +79,6 @@ public:
ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_read) override;
private:
- void
- CloseReadFileDescriptor();
- void
- CloseWriteFileDescriptor();
-
int m_fds[2];
};
diff --git a/include/lldb/Host/posix/ProcessLauncherPosix.h b/include/lldb/Host/posix/ProcessLauncherPosix.h
index c0e2a36e4e5e..a5e57ccb26ed 100644
--- a/include/lldb/Host/posix/ProcessLauncherPosix.h
+++ b/include/lldb/Host/posix/ProcessLauncherPosix.h
@@ -18,7 +18,7 @@ namespace lldb_private
class ProcessLauncherPosix : public ProcessLauncher
{
public:
- virtual HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error);
+ HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) override;
};
}
diff --git a/include/lldb/Initialization/SystemInitializer.h b/include/lldb/Initialization/SystemInitializer.h
new file mode 100644
index 000000000000..c7f98f24ae48
--- /dev/null
+++ b/include/lldb/Initialization/SystemInitializer.h
@@ -0,0 +1,26 @@
+//===-- SystemInitializer.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_INITIALIZATION_SYSTEM_INITIALIZER_H
+#define LLDB_INITIALIZATION_SYSTEM_INITIALIZER_H
+
+namespace lldb_private
+{
+class SystemInitializer
+{
+ public:
+ SystemInitializer();
+ virtual ~SystemInitializer();
+
+ virtual void Initialize() = 0;
+ virtual void Terminate() = 0;
+};
+}
+
+#endif
diff --git a/include/lldb/Initialization/SystemInitializerCommon.h b/include/lldb/Initialization/SystemInitializerCommon.h
new file mode 100644
index 000000000000..af66c93a5e48
--- /dev/null
+++ b/include/lldb/Initialization/SystemInitializerCommon.h
@@ -0,0 +1,38 @@
+//===-- SystemInitializerCommon.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_INITIALIZATION_SYSTEM_INITIALIZER_COMMON_H
+#define LLDB_INITIALIZATION_SYSTEM_INITIALIZER_COMMON_H
+
+#include "SystemInitializer.h"
+
+namespace lldb_private
+{
+//------------------------------------------------------------------
+/// Initializes common lldb functionality.
+///
+/// This class is responsible for initializing a subset of lldb
+/// useful to both debug servers and debug clients. Debug servers
+/// do not use all of LLDB and desire small binary sizes, so this
+/// functionality is separate. This class is used by constructing
+/// an instance of SystemLifetimeManager with this class passed to
+/// the constructor.
+//------------------------------------------------------------------
+class SystemInitializerCommon : public SystemInitializer
+{
+ public:
+ SystemInitializerCommon();
+ virtual ~SystemInitializerCommon();
+
+ void Initialize() override;
+ void Terminate() override;
+};
+}
+
+#endif
diff --git a/include/lldb/Initialization/SystemLifetimeManager.h b/include/lldb/Initialization/SystemLifetimeManager.h
new file mode 100644
index 000000000000..843ec2820677
--- /dev/null
+++ b/include/lldb/Initialization/SystemLifetimeManager.h
@@ -0,0 +1,42 @@
+//===-- SystemLifetimeManager.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_INITIALIZATION_SYSTEM_LIFETIME_MANAGER_H
+#define LLDB_INITIALIZATION_SYSTEM_LIFETIME_MANAGER_H
+
+#include "lldb/lldb-private-types.h"
+#include "lldb/Host/Mutex.h"
+
+#include <memory>
+
+namespace lldb_private
+{
+class SystemInitializer;
+
+class SystemLifetimeManager
+{
+ public:
+ SystemLifetimeManager();
+ ~SystemLifetimeManager();
+
+ void Initialize(std::unique_ptr<SystemInitializer> initializer, LoadPluginCallbackType plugin_callback);
+ void Terminate();
+
+ private:
+ Mutex m_mutex;
+ std::unique_ptr<SystemInitializer> m_initializer;
+ bool m_initialized;
+
+ // Noncopyable.
+ SystemLifetimeManager(const SystemLifetimeManager &other) = delete;
+ SystemLifetimeManager &operator=(const SystemLifetimeManager &other) = delete;
+};
+}
+
+#endif
diff --git a/include/lldb/Interpreter/Args.h b/include/lldb/Interpreter/Args.h
index fe29df468de7..e11636b63f17 100644
--- a/include/lldb/Interpreter/Args.h
+++ b/include/lldb/Interpreter/Args.h
@@ -18,6 +18,7 @@
#include <utility>
// Other libraries and framework includes
+#include "llvm/ADT/StringRef.h"
// Project includes
#include "lldb/lldb-private-types.h"
#include "lldb/lldb-types.h"
@@ -75,11 +76,9 @@ public:
/// A NULL terminated command that will be copied and split up
/// into arguments.
///
- /// @see Args::SetCommandString(const char *)
+ /// @see Args::SetCommandString(llvm::StringRef)
//------------------------------------------------------------------
- Args (const char *command = NULL);
-
- Args (const char *command, size_t len);
+ Args (llvm::StringRef command = llvm::StringRef());
Args (const Args &rhs);
@@ -108,7 +107,7 @@ public:
/// that can be accessed via the accessor functions.
///
/// @param[in] command
- /// A NULL terminated command that will be copied and split up
+ /// A command StringRef that will be copied and split up
/// into arguments.
///
/// @see Args::GetArgumentCount() const
@@ -118,10 +117,7 @@ public:
/// @see Args::Unshift (const char *)
//------------------------------------------------------------------
void
- SetCommandString (const char *command);
-
- void
- SetCommandString (const char *command, size_t len);
+ SetCommandString (llvm::StringRef command);
bool
GetCommandString (std::string &command) const;
@@ -449,6 +445,9 @@ protected:
void
UpdateArgvFromArgs ();
+
+ llvm::StringRef
+ ParseSingleArgument (llvm::StringRef command);
};
} // namespace lldb_private
diff --git a/include/lldb/Interpreter/CommandInterpreter.h b/include/lldb/Interpreter/CommandInterpreter.h
index 20b6ff95be8b..1962050dffcb 100644
--- a/include/lldb/Interpreter/CommandInterpreter.h
+++ b/include/lldb/Interpreter/CommandInterpreter.h
@@ -625,6 +625,12 @@ public:
bool
GetPromptOnQuit () const;
+ void
+ SetPromptOnQuit (bool b);
+
+ void
+ ResolveCommand(const char *command_line, CommandReturnObject &result);
+
bool
GetStopCmdSourceOnError () const;
@@ -685,6 +691,13 @@ private:
Error
PreprocessCommand (std::string &command);
+ // Completely resolves aliases and abbreviations, returning a pointer to the
+ // final command object and updating command_line to the fully substituted
+ // and translated command.
+ CommandObject *
+ ResolveCommandImpl(std::string &command_line, CommandReturnObject &result);
+
+
Debugger &m_debugger; // The debugger session that this interpreter is associated with
ExecutionContextRef m_exe_ctx_ref; // The current execution context to use when handling commands
bool m_synchronous_execution;
diff --git a/include/lldb/Interpreter/CommandObject.h b/include/lldb/Interpreter/CommandObject.h
index bace3264dafa..c0901d5e3032 100644
--- a/include/lldb/Interpreter/CommandObject.h
+++ b/include/lldb/Interpreter/CommandObject.h
@@ -98,7 +98,7 @@ public:
return m_interpreter;
}
- const char *
+ virtual const char *
GetHelp ();
virtual const char *
@@ -114,6 +114,9 @@ public:
SetHelp (const char * str);
void
+ SetHelp (std::string str);
+
+ void
SetHelpLong (const char * str);
void
@@ -192,7 +195,7 @@ public:
static lldb::CommandArgumentType
LookupArgumentName (const char *arg_name);
- static ArgumentTableEntry *
+ static const ArgumentTableEntry *
FindArgumentDataByType (lldb::CommandArgumentType arg_type);
int
@@ -217,89 +220,6 @@ public:
bool
IsPairType (ArgumentRepetitionType arg_repeat_type);
-
- enum
- {
- //----------------------------------------------------------------------
- // eFlagRequiresTarget
- //
- // Ensures a valid target is contained in m_exe_ctx prior to executing
- // the command. If a target doesn't exist or is invalid, the command
- // will fail and CommandObject::GetInvalidTargetDescription() will be
- // returned as the error. CommandObject subclasses can override the
- // virtual function for GetInvalidTargetDescription() to provide custom
- // strings when needed.
- //----------------------------------------------------------------------
- eFlagRequiresTarget = (1u << 0),
- //----------------------------------------------------------------------
- // eFlagRequiresProcess
- //
- // Ensures a valid process is contained in m_exe_ctx prior to executing
- // the command. If a process doesn't exist or is invalid, the command
- // will fail and CommandObject::GetInvalidProcessDescription() will be
- // returned as the error. CommandObject subclasses can override the
- // virtual function for GetInvalidProcessDescription() to provide custom
- // strings when needed.
- //----------------------------------------------------------------------
- eFlagRequiresProcess = (1u << 1),
- //----------------------------------------------------------------------
- // eFlagRequiresThread
- //
- // Ensures a valid thread is contained in m_exe_ctx prior to executing
- // the command. If a thread doesn't exist or is invalid, the command
- // will fail and CommandObject::GetInvalidThreadDescription() will be
- // returned as the error. CommandObject subclasses can override the
- // virtual function for GetInvalidThreadDescription() to provide custom
- // strings when needed.
- //----------------------------------------------------------------------
- eFlagRequiresThread = (1u << 2),
- //----------------------------------------------------------------------
- // eFlagRequiresFrame
- //
- // Ensures a valid frame is contained in m_exe_ctx prior to executing
- // the command. If a frame doesn't exist or is invalid, the command
- // will fail and CommandObject::GetInvalidFrameDescription() will be
- // returned as the error. CommandObject subclasses can override the
- // virtual function for GetInvalidFrameDescription() to provide custom
- // strings when needed.
- //----------------------------------------------------------------------
- eFlagRequiresFrame = (1u << 3),
- //----------------------------------------------------------------------
- // eFlagRequiresRegContext
- //
- // 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 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
- // for GetInvalidRegContextDescription() to provide custom strings when
- // needed.
- //----------------------------------------------------------------------
- eFlagRequiresRegContext = (1u << 4),
- //----------------------------------------------------------------------
- // eFlagTryTargetAPILock
- //
- // Attempts to acquire the target lock if a target is selected in the
- // command interpreter. If the command object fails to acquire the API
- // lock, the command will fail with an appropriate error message.
- //----------------------------------------------------------------------
- eFlagTryTargetAPILock = (1u << 5),
- //----------------------------------------------------------------------
- // eFlagProcessMustBeLaunched
- //
- // Verifies that there is a launched process in m_exe_ctx, if there
- // isn't, the command will fail with an appropriate error message.
- //----------------------------------------------------------------------
- eFlagProcessMustBeLaunched = (1u << 6),
- //----------------------------------------------------------------------
- // eFlagProcessMustBePaused
- //
- // Verifies that there is a paused process in m_exe_ctx, if there
- // isn't, the command will fail with an appropriate error message.
- //----------------------------------------------------------------------
- eFlagProcessMustBePaused = (1u << 7)
- };
bool
ParseOptions (Args& args, CommandReturnObject &result);
diff --git a/include/lldb/Interpreter/OptionValue.h b/include/lldb/Interpreter/OptionValue.h
index 787430a96ef5..fd751f744de6 100644
--- a/include/lldb/Interpreter/OptionValue.h
+++ b/include/lldb/Interpreter/OptionValue.h
@@ -40,6 +40,7 @@ namespace lldb_private {
eTypeFileSpec,
eTypeFileSpecList,
eTypeFormat,
+ eTypeLanguage,
eTypePathMap,
eTypeProperties,
eTypeRegex,
@@ -106,7 +107,7 @@ namespace lldb_private {
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) = 0;
virtual Error
- SetValueFromCString (const char *value, VarSetOperationType op = eVarSetOperationAssign);
+ SetValueFromString (llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign);
virtual bool
Clear () = 0;
@@ -187,6 +188,7 @@ namespace lldb_private {
case 1u << eTypeFileSpec: return eTypeFileSpec;
case 1u << eTypeFileSpecList: return eTypeFileSpecList;
case 1u << eTypeFormat: return eTypeFormat;
+ case 1u << eTypeLanguage: return eTypeLanguage;
case 1u << eTypePathMap: return eTypePathMap;
case 1u << eTypeProperties: return eTypeProperties;
case 1u << eTypeRegex: return eTypeRegex;
@@ -270,6 +272,12 @@ namespace lldb_private {
const OptionValueFormat *
GetAsFormat () const;
+ OptionValueLanguage *
+ GetAsLanguage ();
+
+ const OptionValueLanguage *
+ GetAsLanguage () const;
+
OptionValuePathMappings *
GetAsPathMappings ();
@@ -348,6 +356,12 @@ namespace lldb_private {
bool
SetFormatValue (lldb::Format new_value);
+
+ lldb::LanguageType
+ GetLanguageValue (lldb::LanguageType fail_value = lldb::eLanguageTypeUnknown) const;
+
+ bool
+ SetLanguageValue (lldb::LanguageType new_language);
const FormatEntity::Entry *
GetFormatEntity () const;
diff --git a/include/lldb/Interpreter/OptionValueArch.h b/include/lldb/Interpreter/OptionValueArch.h
index 662e1ec9f627..3d5d72619efc 100644
--- a/include/lldb/Interpreter/OptionValueArch.h
+++ b/include/lldb/Interpreter/OptionValueArch.h
@@ -71,7 +71,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueArray.h b/include/lldb/Interpreter/OptionValueArray.h
index 39ae2f6f43d6..2e44f9f07438 100644
--- a/include/lldb/Interpreter/OptionValueArray.h
+++ b/include/lldb/Interpreter/OptionValueArray.h
@@ -49,7 +49,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueBoolean.h b/include/lldb/Interpreter/OptionValueBoolean.h
index e024f3a0f3db..214fd1649d39 100644
--- a/include/lldb/Interpreter/OptionValueBoolean.h
+++ b/include/lldb/Interpreter/OptionValueBoolean.h
@@ -54,7 +54,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueChar.h b/include/lldb/Interpreter/OptionValueChar.h
index 55f4b63538ea..8fc02093e3d9 100644
--- a/include/lldb/Interpreter/OptionValueChar.h
+++ b/include/lldb/Interpreter/OptionValueChar.h
@@ -54,7 +54,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueDictionary.h b/include/lldb/Interpreter/OptionValueDictionary.h
index 5fb698b9f221..efa15dd6ef88 100644
--- a/include/lldb/Interpreter/OptionValueDictionary.h
+++ b/include/lldb/Interpreter/OptionValueDictionary.h
@@ -50,7 +50,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueEnumeration.h b/include/lldb/Interpreter/OptionValueEnumeration.h
index 68beddfce0d0..e820729385de 100644
--- a/include/lldb/Interpreter/OptionValueEnumeration.h
+++ b/include/lldb/Interpreter/OptionValueEnumeration.h
@@ -55,7 +55,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueFileSpec.h b/include/lldb/Interpreter/OptionValueFileSpec.h
index 7e74b605660c..80dd77ecef2a 100644
--- a/include/lldb/Interpreter/OptionValueFileSpec.h
+++ b/include/lldb/Interpreter/OptionValueFileSpec.h
@@ -22,12 +22,14 @@ namespace lldb_private {
class OptionValueFileSpec : public OptionValue
{
public:
- OptionValueFileSpec ();
+ OptionValueFileSpec (bool resolve = true);
- OptionValueFileSpec (const FileSpec &value);
+ OptionValueFileSpec (const FileSpec &value,
+ bool resolve = true);
OptionValueFileSpec (const FileSpec &current_value,
- const FileSpec &default_value);
+ const FileSpec &default_value,
+ bool resolve = true);
virtual
~OptionValueFileSpec()
@@ -48,7 +50,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
@@ -57,6 +59,7 @@ public:
m_current_value = m_default_value;
m_value_was_set = false;
m_data_sp.reset();
+ m_data_mod_time.Clear();
return true;
}
@@ -121,7 +124,9 @@ protected:
FileSpec m_current_value;
FileSpec m_default_value;
lldb::DataBufferSP m_data_sp;
+ TimeValue m_data_mod_time;
uint32_t m_completion_mask;
+ bool m_resolve;
};
} // namespace lldb_private
diff --git a/include/lldb/Interpreter/OptionValueFileSpecList.h b/include/lldb/Interpreter/OptionValueFileSpecList.h
index 792de4e23af6..a105d22e45f9 100644
--- a/include/lldb/Interpreter/OptionValueFileSpecList.h
+++ b/include/lldb/Interpreter/OptionValueFileSpecList.h
@@ -54,7 +54,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueFormat.h b/include/lldb/Interpreter/OptionValueFormat.h
index 245b2eeb5af1..06ed12854318 100644
--- a/include/lldb/Interpreter/OptionValueFormat.h
+++ b/include/lldb/Interpreter/OptionValueFormat.h
@@ -55,7 +55,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueFormatEntity.h b/include/lldb/Interpreter/OptionValueFormatEntity.h
index cc988998bda0..18ace3a6a1b6 100644
--- a/include/lldb/Interpreter/OptionValueFormatEntity.h
+++ b/include/lldb/Interpreter/OptionValueFormatEntity.h
@@ -43,7 +43,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) override;
Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
bool
diff --git a/include/lldb/Interpreter/OptionValueLanguage.h b/include/lldb/Interpreter/OptionValueLanguage.h
new file mode 100644
index 000000000000..fba5e22821e0
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueLanguage.h
@@ -0,0 +1,107 @@
+//===-- OptionValueLanguage.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_OptionValueLanguage_h_
+#define liblldb_OptionValueLanguage_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueLanguage : public OptionValue
+{
+public:
+ OptionValueLanguage (lldb::LanguageType value) :
+ OptionValue(),
+ m_current_value (value),
+ m_default_value (value)
+ {
+ }
+
+ OptionValueLanguage (lldb::LanguageType current_value,
+ lldb::LanguageType default_value) :
+ OptionValue(),
+ m_current_value (current_value),
+ m_default_value (default_value)
+ {
+ }
+
+ virtual
+ ~OptionValueLanguage ()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ OptionValue::Type
+ GetType () const override
+ {
+ return eTypeLanguage;
+ }
+
+ void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) override;
+
+ Error
+ SetValueFromString (llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override;
+
+ bool
+ Clear () override
+ {
+ m_current_value = m_default_value;
+ m_value_was_set = false;
+ return true;
+ }
+
+ lldb::OptionValueSP
+ DeepCopy () const override;
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ lldb::LanguageType
+ GetCurrentValue() const
+ {
+ return m_current_value;
+ }
+
+ lldb::LanguageType
+ GetDefaultValue() const
+ {
+ return m_default_value;
+ }
+
+ void
+ SetCurrentValue (lldb::LanguageType value)
+ {
+ m_current_value = value;
+ }
+
+ void
+ SetDefaultValue (lldb::LanguageType value)
+ {
+ m_default_value = value;
+ }
+
+protected:
+ lldb::LanguageType m_current_value;
+ lldb::LanguageType m_default_value;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueLanguage_h_
diff --git a/include/lldb/Interpreter/OptionValuePathMappings.h b/include/lldb/Interpreter/OptionValuePathMappings.h
index 7ebf4947c6af..7b476a9cd366 100644
--- a/include/lldb/Interpreter/OptionValuePathMappings.h
+++ b/include/lldb/Interpreter/OptionValuePathMappings.h
@@ -48,7 +48,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueProperties.h b/include/lldb/Interpreter/OptionValueProperties.h
index 6f7f4995ed15..405beefff6d1 100644
--- a/include/lldb/Interpreter/OptionValueProperties.h
+++ b/include/lldb/Interpreter/OptionValueProperties.h
@@ -61,7 +61,7 @@ public:
DeepCopy () const;
virtual Error
- SetValueFromCString (const char *value, VarSetOperationType op = eVarSetOperationAssign);
+ SetValueFromString (llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign);
virtual void
DumpValue (const ExecutionContext *exe_ctx,
diff --git a/include/lldb/Interpreter/OptionValueRegex.h b/include/lldb/Interpreter/OptionValueRegex.h
index 295bb98b69e6..5e04218dbfdf 100644
--- a/include/lldb/Interpreter/OptionValueRegex.h
+++ b/include/lldb/Interpreter/OptionValueRegex.h
@@ -49,7 +49,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueSInt64.h b/include/lldb/Interpreter/OptionValueSInt64.h
index 8bc8fb2da2d5..36ae97ccfcf8 100644
--- a/include/lldb/Interpreter/OptionValueSInt64.h
+++ b/include/lldb/Interpreter/OptionValueSInt64.h
@@ -77,7 +77,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueString.h b/include/lldb/Interpreter/OptionValueString.h
index a82e1403b74b..c75745d402be 100644
--- a/include/lldb/Interpreter/OptionValueString.h
+++ b/include/lldb/Interpreter/OptionValueString.h
@@ -137,7 +137,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueUInt64.h b/include/lldb/Interpreter/OptionValueUInt64.h
index 9b5496f9835c..51ff8818dcff 100644
--- a/include/lldb/Interpreter/OptionValueUInt64.h
+++ b/include/lldb/Interpreter/OptionValueUInt64.h
@@ -70,7 +70,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValueUUID.h b/include/lldb/Interpreter/OptionValueUUID.h
index caf436e576f5..c6ab48a627f6 100644
--- a/include/lldb/Interpreter/OptionValueUUID.h
+++ b/include/lldb/Interpreter/OptionValueUUID.h
@@ -53,7 +53,7 @@ public:
DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
virtual Error
- SetValueFromCString (const char *value,
+ SetValueFromString (llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
virtual bool
diff --git a/include/lldb/Interpreter/OptionValues.h b/include/lldb/Interpreter/OptionValues.h
index 2ccab994674b..44e1f0975826 100644
--- a/include/lldb/Interpreter/OptionValues.h
+++ b/include/lldb/Interpreter/OptionValues.h
@@ -21,6 +21,7 @@
#include "lldb/Interpreter/OptionValueFileSpec.h"
#include "lldb/Interpreter/OptionValueFileSpecList.h"
#include "lldb/Interpreter/OptionValueFormat.h"
+#include "lldb/Interpreter/OptionValueLanguage.h"
#include "lldb/Interpreter/OptionValueFormatEntity.h"
#include "lldb/Interpreter/OptionValuePathMappings.h"
#include "lldb/Interpreter/OptionValueProperties.h"
diff --git a/include/lldb/Interpreter/PythonDataObjects.h b/include/lldb/Interpreter/PythonDataObjects.h
index a1145b6f33d9..df281b533cba 100644
--- a/include/lldb/Interpreter/PythonDataObjects.h
+++ b/include/lldb/Interpreter/PythonDataObjects.h
@@ -17,12 +17,61 @@
// Project includes
#include "lldb/lldb-defines.h"
#include "lldb/Core/ConstString.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Core/Flags.h"
#include "lldb/Interpreter/OptionValue.h"
#include "lldb/lldb-python.h"
namespace lldb_private {
-
+class PythonString;
+class PythonList;
+class PythonDictionary;
+class PythonObject;
+class PythonInteger;
+
+class StructuredPythonObject : public StructuredData::Generic
+{
+ public:
+ StructuredPythonObject()
+ : StructuredData::Generic()
+ {
+ }
+
+ StructuredPythonObject(void *obj)
+ : StructuredData::Generic(obj)
+ {
+ Py_XINCREF(GetValue());
+ }
+
+ virtual ~StructuredPythonObject()
+ {
+ if (Py_IsInitialized())
+ Py_XDECREF(GetValue());
+ SetValue(nullptr);
+ }
+
+ bool
+ IsValid() const override
+ {
+ return GetValue() && GetValue() != Py_None;
+ }
+
+ void Dump(Stream &s) const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StructuredPythonObject);
+};
+
+enum class PyObjectType
+{
+ Unknown,
+ None,
+ Integer,
+ Dictionary,
+ List,
+ String
+};
+
class PythonObject
{
public:
@@ -42,8 +91,6 @@ namespace lldb_private {
{
Reset (rhs.m_py_obj);
}
-
- explicit PythonObject (const lldb::ScriptInterpreterObjectSP &script_object_sp);
virtual
~PythonObject ()
@@ -89,6 +136,8 @@ namespace lldb_private {
return m_py_obj;
}
+ PyObjectType GetObjectType() const;
+
PythonString
Repr ();
@@ -102,7 +151,9 @@ namespace lldb_private {
bool
IsNULLOrNone () const;
-
+
+ StructuredData::ObjectSP CreateStructuredObject() const;
+
protected:
PyObject* m_py_obj;
};
@@ -110,25 +161,25 @@ namespace lldb_private {
class PythonString: public PythonObject
{
public:
-
PythonString ();
PythonString (PyObject *o);
PythonString (const PythonObject &object);
- PythonString (const lldb::ScriptInterpreterObjectSP &script_object_sp);
- PythonString (const char* string);
+ PythonString (llvm::StringRef string);
+ PythonString (const char *string);
virtual ~PythonString ();
-
+
virtual bool
Reset (PyObject* py_obj = NULL);
- const char*
+ llvm::StringRef
GetString() const;
size_t
GetSize() const;
- void
- SetString (const char* string);
+ void SetString(llvm::StringRef string);
+
+ StructuredData::StringSP CreateStructuredString() const;
};
class PythonInteger: public PythonObject
@@ -138,18 +189,18 @@ namespace lldb_private {
PythonInteger ();
PythonInteger (PyObject* py_obj);
PythonInteger (const PythonObject &object);
- PythonInteger (const lldb::ScriptInterpreterObjectSP &script_object_sp);
PythonInteger (int64_t value);
virtual ~PythonInteger ();
virtual bool
Reset (PyObject* py_obj = NULL);
-
- int64_t
- GetInteger();
-
+
+ int64_t GetInteger() const;
+
void
SetInteger (int64_t value);
+
+ StructuredData::IntegerSP CreateStructuredInteger() const;
};
class PythonList: public PythonObject
@@ -159,24 +210,23 @@ namespace lldb_private {
PythonList (bool create_empty);
PythonList (PyObject* py_obj);
PythonList (const PythonObject &object);
- PythonList (const lldb::ScriptInterpreterObjectSP &script_object_sp);
PythonList (uint32_t count);
virtual ~PythonList ();
virtual bool
Reset (PyObject* py_obj = NULL);
-
- uint32_t
- GetSize();
-
- PythonObject
- GetItemAtIndex (uint32_t index);
-
+
+ uint32_t GetSize() const;
+
+ PythonObject GetItemAtIndex(uint32_t index) const;
+
void
SetItemAtIndex (uint32_t index, const PythonObject &object);
void
AppendItem (const PythonObject &object);
+
+ StructuredData::ArraySP CreateStructuredArray() const;
};
class PythonDictionary: public PythonObject
@@ -186,14 +236,13 @@ namespace lldb_private {
explicit PythonDictionary (bool create_empty);
PythonDictionary (PyObject* object);
PythonDictionary (const PythonObject &object);
- PythonDictionary (const lldb::ScriptInterpreterObjectSP &script_object_sp);
virtual ~PythonDictionary ();
virtual bool
Reset (PyObject* object = NULL);
-
- uint32_t GetSize();
-
+
+ uint32_t GetSize() const;
+
PythonObject
GetItemForKey (const PythonString &key) const;
@@ -222,6 +271,8 @@ namespace lldb_private {
void
SetItemForKey (const PythonString &key, const PythonObject& value);
+
+ StructuredData::DictionarySP CreateStructuredDictionary() const;
};
} // namespace lldb_private
diff --git a/include/lldb/Interpreter/ScriptInterpreter.h b/include/lldb/Interpreter/ScriptInterpreter.h
index 1b4b88161927..0f45dd8245e9 100644
--- a/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/include/lldb/Interpreter/ScriptInterpreter.h
@@ -14,53 +14,12 @@
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Error.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Utility/PseudoTerminal.h"
namespace lldb_private {
-
-class ScriptInterpreterObject
-{
-public:
- ScriptInterpreterObject() :
- m_object(NULL)
- {}
-
- ScriptInterpreterObject(void* obj) :
- m_object(obj)
- {}
-
- ScriptInterpreterObject(const ScriptInterpreterObject& rhs)
- : m_object(rhs.m_object)
- {}
-
- virtual void*
- GetObject()
- {
- return m_object;
- }
-
- explicit operator bool ()
- {
- return m_object != NULL;
- }
-
- ScriptInterpreterObject&
- operator = (const ScriptInterpreterObject& rhs)
- {
- if (this != &rhs)
- m_object = rhs.m_object;
- return *this;
- }
-
- virtual
- ~ScriptInterpreterObject()
- {}
-
-protected:
- void* m_object;
-};
class ScriptInterpreterLocker
{
@@ -82,87 +41,6 @@ class ScriptInterpreter
{
public:
- typedef void (*SWIGInitCallback) (void);
-
- typedef bool (*SWIGBreakpointCallbackFunction) (const char *python_function_name,
- const char *session_dictionary_name,
- const lldb::StackFrameSP& frame_sp,
- const lldb::BreakpointLocationSP &bp_loc_sp);
-
- typedef bool (*SWIGWatchpointCallbackFunction) (const char *python_function_name,
- const char *session_dictionary_name,
- const lldb::StackFrameSP& frame_sp,
- const lldb::WatchpointSP &wp_sp);
-
- typedef bool (*SWIGPythonTypeScriptCallbackFunction) (const char *python_function_name,
- void *session_dictionary,
- const lldb::ValueObjectSP& valobj_sp,
- void** pyfunct_wrapper,
- const lldb::TypeSummaryOptionsSP& options,
- std::string& retval);
-
- typedef void* (*SWIGPythonCreateSyntheticProvider) (const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::ValueObjectSP& valobj_sp);
-
- typedef void* (*SWIGPythonCreateScriptedThreadPlan) (const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::ThreadPlanSP& thread_plan_sp);
-
- typedef bool (*SWIGPythonCallThreadPlan) (void *implementor, const char *method_name, Event *event_sp, bool &got_error);
-
- typedef void* (*SWIGPythonCreateOSPlugin) (const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::ProcessSP& process_sp);
-
- typedef uint32_t (*SWIGPythonCalculateNumChildren) (void *implementor);
- typedef void* (*SWIGPythonGetChildAtIndex) (void *implementor, uint32_t idx);
- typedef int (*SWIGPythonGetIndexOfChildWithName) (void *implementor, const char* child_name);
- typedef void* (*SWIGPythonCastPyObjectToSBValue) (void* data);
- typedef lldb::ValueObjectSP (*SWIGPythonGetValueObjectSPFromSBValue) (void* data);
- typedef bool (*SWIGPythonUpdateSynthProviderInstance) (void* data);
- typedef bool (*SWIGPythonMightHaveChildrenSynthProviderInstance) (void* data);
- typedef void* (*SWIGPythonGetValueSynthProviderInstance) (void *implementor);
-
- typedef bool (*SWIGPythonCallCommand) (const char *python_function_name,
- const char *session_dictionary_name,
- lldb::DebuggerSP& debugger,
- const char* args,
- lldb_private::CommandReturnObject& cmd_retobj,
- lldb::ExecutionContextRefSP exe_ctx_ref_sp);
-
- typedef bool (*SWIGPythonCallModuleInit) (const char *python_module_name,
- const char *session_dictionary_name,
- lldb::DebuggerSP& debugger);
-
- typedef bool (*SWIGPythonScriptKeyword_Process) (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::ProcessSP& process,
- std::string& output);
- typedef bool (*SWIGPythonScriptKeyword_Thread) (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::ThreadSP& thread,
- std::string& output);
-
- typedef bool (*SWIGPythonScriptKeyword_Target) (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::TargetSP& target,
- std::string& output);
-
- typedef bool (*SWIGPythonScriptKeyword_Frame) (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::StackFrameSP& frame,
- std::string& output);
-
- typedef bool (*SWIGPythonScriptKeyword_Value) (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::ValueObjectSP& value,
- std::string& output);
-
- typedef void* (*SWIGPython_GetDynamicSetting) (void* module,
- const char* setting,
- const lldb::TargetSP& target_sp);
-
typedef enum
{
eScriptReturnTypeCharPtr,
@@ -324,95 +202,87 @@ public:
{
return false;
}
-
- virtual lldb::ScriptInterpreterObjectSP
- CreateSyntheticScriptedProvider (const char *class_name,
- lldb::ValueObjectSP valobj)
+
+ virtual StructuredData::ObjectSP
+ CreateSyntheticScriptedProvider(const char *class_name, lldb::ValueObjectSP valobj)
{
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::ObjectSP();
}
-
- virtual lldb::ScriptInterpreterObjectSP
+
+ virtual StructuredData::GenericSP
+ CreateScriptCommandObject (const char *class_name)
+ {
+ return StructuredData::GenericSP();
+ }
+
+ virtual StructuredData::GenericSP
OSPlugin_CreatePluginObject (const char *class_name,
lldb::ProcessSP process_sp)
{
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::GenericSP();
}
-
- virtual lldb::ScriptInterpreterObjectSP
- OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp)
+
+ virtual StructuredData::DictionarySP
+ OSPlugin_RegisterInfo(StructuredData::ObjectSP os_plugin_object_sp)
{
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::DictionarySP();
}
-
- virtual lldb::ScriptInterpreterObjectSP
- OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp)
+
+ virtual StructuredData::ArraySP
+ OSPlugin_ThreadsInfo(StructuredData::ObjectSP os_plugin_object_sp)
{
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::ArraySP();
}
-
- virtual lldb::ScriptInterpreterObjectSP
- OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
- lldb::tid_t thread_id)
+
+ virtual StructuredData::StringSP
+ OSPlugin_RegisterContextData(StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t thread_id)
{
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::StringSP();
}
- virtual lldb::ScriptInterpreterObjectSP
- OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
- lldb::tid_t tid,
- lldb::addr_t context)
+ virtual StructuredData::DictionarySP
+ OSPlugin_CreateThread(StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t tid, lldb::addr_t context)
{
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::DictionarySP();
}
-
- virtual lldb::ScriptInterpreterObjectSP
- CreateScriptedThreadPlan (const char *class_name,
- lldb::ThreadPlanSP thread_plan_sp)
+
+ virtual StructuredData::ObjectSP
+ CreateScriptedThreadPlan(const char *class_name, lldb::ThreadPlanSP thread_plan_sp)
{
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::ObjectSP();
}
virtual bool
- ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp,
- Event *event,
- bool &script_error)
+ ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error)
{
script_error = true;
return true;
}
virtual bool
- ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp,
- Event *event,
- bool &script_error)
+ ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error)
{
script_error = true;
return true;
}
virtual lldb::StateType
- ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp,
- bool &script_error)
+ ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp, bool &script_error)
{
script_error = true;
return lldb::eStateStepping;
}
- virtual lldb::ScriptInterpreterObjectSP
- LoadPluginModule (const FileSpec& file_spec,
- lldb_private::Error& error)
+ virtual StructuredData::ObjectSP
+ LoadPluginModule(const FileSpec &file_spec, lldb_private::Error &error)
{
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::ObjectSP();
}
-
- virtual lldb::ScriptInterpreterObjectSP
- GetDynamicSettings (lldb::ScriptInterpreterObjectSP plugin_module_sp,
- Target* target,
- const char* setting_name,
- lldb_private::Error& error)
+
+ virtual StructuredData::DictionarySP
+ GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target, const char *setting_name, lldb_private::Error &error)
{
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::DictionarySP();
}
virtual Error
@@ -464,13 +334,10 @@ public:
{
return;
}
-
+
virtual bool
- GetScriptedSummary (const char *function_name,
- lldb::ValueObjectSP valobj,
- lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
- const TypeSummaryOptions& options,
- std::string& retval)
+ GetScriptedSummary(const char *function_name, lldb::ValueObjectSP valobj, StructuredData::ObjectSP &callee_wrapper_sp,
+ const TypeSummaryOptions &options, std::string &retval)
{
return false;
}
@@ -480,39 +347,39 @@ public:
{
// Clean up any ref counts to SBObjects that might be in global variables
}
-
+
virtual size_t
- CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor)
+ CalculateNumChildren(const StructuredData::ObjectSP &implementor)
{
return 0;
}
-
+
virtual lldb::ValueObjectSP
- GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor, uint32_t idx)
+ GetChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx)
{
return lldb::ValueObjectSP();
}
-
+
virtual int
- GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor, const char* child_name)
+ GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor, const char *child_name)
{
return UINT32_MAX;
}
-
+
virtual bool
- UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor)
+ UpdateSynthProviderInstance(const StructuredData::ObjectSP &implementor)
{
return false;
}
-
+
virtual bool
- MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor)
+ MightHaveChildrenSynthProviderInstance(const StructuredData::ObjectSP &implementor)
{
return true;
}
-
+
virtual lldb::ValueObjectSP
- GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor)
+ GetSyntheticValue(const StructuredData::ObjectSP &implementor)
{
return nullptr;
}
@@ -529,6 +396,17 @@ public:
}
virtual bool
+ RunScriptBasedCommand (StructuredData::GenericSP impl_obj_sp,
+ const char* args,
+ ScriptedCommandSynchronicity synchronicity,
+ lldb_private::CommandReturnObject& cmd_retobj,
+ Error& error,
+ const lldb_private::ExecutionContext& exe_ctx)
+ {
+ return false;
+ }
+
+ virtual bool
RunScriptFormatKeyword (const char* impl_function,
Process* process,
std::string& output,
@@ -586,26 +464,45 @@ public:
}
virtual bool
+ GetShortHelpForCommandObject (StructuredData::GenericSP cmd_obj_sp,
+ std::string& dest)
+ {
+ dest.clear();
+ return false;
+ }
+
+ virtual uint32_t
+ GetFlagsForCommandObject (StructuredData::GenericSP cmd_obj_sp)
+ {
+ return 0;
+ }
+
+ virtual bool
+ GetLongHelpForCommandObject (StructuredData::GenericSP cmd_obj_sp,
+ std::string& dest)
+ {
+ dest.clear();
+ return false;
+ }
+
+ virtual bool
CheckObjectExists (const char* name)
{
return false;
}
virtual bool
- LoadScriptingModule (const char* filename,
- bool can_reload,
- bool init_session,
- lldb_private::Error& error,
- lldb::ScriptInterpreterObjectSP* module_sp = nullptr)
+ LoadScriptingModule(const char *filename, bool can_reload, bool init_session, lldb_private::Error &error,
+ StructuredData::ObjectSP *module_sp = nullptr)
{
error.SetErrorString("loading unimplemented");
return false;
}
-
- virtual lldb::ScriptInterpreterObjectSP
- MakeScriptObject (void* object)
+
+ virtual bool
+ IsReservedWord (const char* word)
{
- return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterObject(object));
+ return false;
}
virtual std::unique_ptr<ScriptInterpreterLocker>
@@ -622,32 +519,6 @@ public:
static std::string
LanguageToString (lldb::ScriptLanguage language);
-
- static void
- InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
- SWIGBreakpointCallbackFunction swig_breakpoint_callback,
- SWIGWatchpointCallbackFunction swig_watchpoint_callback,
- SWIGPythonTypeScriptCallbackFunction swig_typescript_callback,
- SWIGPythonCreateSyntheticProvider swig_synthetic_script,
- SWIGPythonCalculateNumChildren swig_calc_children,
- SWIGPythonGetChildAtIndex swig_get_child_index,
- SWIGPythonGetIndexOfChildWithName swig_get_index_child,
- SWIGPythonCastPyObjectToSBValue swig_cast_to_sbvalue ,
- SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue,
- SWIGPythonUpdateSynthProviderInstance swig_update_provider,
- SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider,
- SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider,
- SWIGPythonCallCommand swig_call_command,
- SWIGPythonCallModuleInit swig_call_module_init,
- SWIGPythonCreateOSPlugin swig_create_os_plugin,
- SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
- SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
- SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
- SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame,
- SWIGPythonScriptKeyword_Value swig_run_script_keyword_value,
- SWIGPython_GetDynamicSetting swig_plugin_get,
- SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script,
- SWIGPythonCallThreadPlan swig_call_thread_plan);
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 94ed16e02ca2..058058ecccb5 100644
--- a/include/lldb/Interpreter/ScriptInterpreterPython.h
+++ b/include/lldb/Interpreter/ScriptInterpreterPython.h
@@ -33,8 +33,99 @@ class ScriptInterpreterPython :
public IOHandlerDelegateMultiline
{
public:
-
- friend class IOHandlerPythonInterpreter;
+ typedef void (*SWIGInitCallback) (void);
+
+ typedef bool (*SWIGBreakpointCallbackFunction) (const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::StackFrameSP& frame_sp,
+ const lldb::BreakpointLocationSP &bp_loc_sp);
+
+ typedef bool (*SWIGWatchpointCallbackFunction) (const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::StackFrameSP& frame_sp,
+ const lldb::WatchpointSP &wp_sp);
+
+ typedef bool (*SWIGPythonTypeScriptCallbackFunction) (const char *python_function_name,
+ void *session_dictionary,
+ const lldb::ValueObjectSP& valobj_sp,
+ void** pyfunct_wrapper,
+ const lldb::TypeSummaryOptionsSP& options,
+ std::string& retval);
+
+ typedef void* (*SWIGPythonCreateSyntheticProvider) (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ValueObjectSP& valobj_sp);
+
+ typedef void* (*SWIGPythonCreateCommandObject) (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::DebuggerSP debugger_sp);
+
+ typedef void* (*SWIGPythonCreateScriptedThreadPlan) (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ThreadPlanSP& thread_plan_sp);
+
+ typedef bool (*SWIGPythonCallThreadPlan) (void *implementor, const char *method_name, Event *event_sp, bool &got_error);
+
+ typedef void* (*SWIGPythonCreateOSPlugin) (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ProcessSP& process_sp);
+
+ typedef size_t (*SWIGPythonCalculateNumChildren) (void *implementor);
+ typedef void* (*SWIGPythonGetChildAtIndex) (void *implementor, uint32_t idx);
+ typedef int (*SWIGPythonGetIndexOfChildWithName) (void *implementor, const char* child_name);
+ typedef void* (*SWIGPythonCastPyObjectToSBValue) (void* data);
+ typedef lldb::ValueObjectSP (*SWIGPythonGetValueObjectSPFromSBValue) (void* data);
+ typedef bool (*SWIGPythonUpdateSynthProviderInstance) (void* data);
+ typedef bool (*SWIGPythonMightHaveChildrenSynthProviderInstance) (void* data);
+ typedef void* (*SWIGPythonGetValueSynthProviderInstance) (void *implementor);
+
+ typedef bool (*SWIGPythonCallCommand) (const char *python_function_name,
+ const char *session_dictionary_name,
+ lldb::DebuggerSP& debugger,
+ const char* args,
+ lldb_private::CommandReturnObject& cmd_retobj,
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp);
+
+ typedef bool (*SWIGPythonCallCommandObject) (void *implementor,
+ lldb::DebuggerSP& debugger,
+ const char* args,
+ lldb_private::CommandReturnObject& cmd_retobj,
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp);
+
+
+ typedef bool (*SWIGPythonCallModuleInit) (const char *python_module_name,
+ const char *session_dictionary_name,
+ lldb::DebuggerSP& debugger);
+
+ typedef bool (*SWIGPythonScriptKeyword_Process) (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ProcessSP& process,
+ std::string& output);
+ typedef bool (*SWIGPythonScriptKeyword_Thread) (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ThreadSP& thread,
+ std::string& output);
+
+ typedef bool (*SWIGPythonScriptKeyword_Target) (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::TargetSP& target,
+ std::string& output);
+
+ typedef bool (*SWIGPythonScriptKeyword_Frame) (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::StackFrameSP& frame,
+ std::string& output);
+
+ typedef bool (*SWIGPythonScriptKeyword_Value) (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ValueObjectSP& value,
+ std::string& output);
+
+ typedef void* (*SWIGPython_GetDynamicSetting) (void* module,
+ const char* setting,
+ const lldb::TargetSP& target_sp);
+
+ friend class ::IOHandlerPythonInterpreter;
ScriptInterpreterPython (CommandInterpreter &interpreter);
@@ -79,74 +170,45 @@ public:
bool
GenerateScriptAliasFunction (StringList &input, std::string& output) override;
-
- lldb::ScriptInterpreterObjectSP
- CreateSyntheticScriptedProvider (const char *class_name,
- lldb::ValueObjectSP valobj) override;
- lldb::ScriptInterpreterObjectSP
- CreateScriptedThreadPlan (const char *class_name,
- lldb::ThreadPlanSP thread_plan) override;
+ StructuredData::ObjectSP CreateSyntheticScriptedProvider(const char *class_name, lldb::ValueObjectSP valobj) override;
+
+ StructuredData::GenericSP CreateScriptCommandObject (const char *class_name) override;
+
+ StructuredData::ObjectSP CreateScriptedThreadPlan(const char *class_name, lldb::ThreadPlanSP thread_plan) override;
+
+ bool ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) override;
+ bool ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) override;
+ lldb::StateType ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp, bool &script_error) override;
+
+ StructuredData::GenericSP OSPlugin_CreatePluginObject(const char *class_name, lldb::ProcessSP process_sp) override;
+
+ StructuredData::DictionarySP OSPlugin_RegisterInfo(StructuredData::ObjectSP os_plugin_object_sp) override;
+
+ StructuredData::ArraySP OSPlugin_ThreadsInfo(StructuredData::ObjectSP os_plugin_object_sp) override;
+
+ StructuredData::StringSP OSPlugin_RegisterContextData(StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t thread_id) override;
+
+ StructuredData::DictionarySP OSPlugin_CreateThread(StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t tid,
+ lldb::addr_t context) override;
+
+ StructuredData::ObjectSP LoadPluginModule(const FileSpec &file_spec, lldb_private::Error &error) override;
+
+ StructuredData::DictionarySP GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target, const char *setting_name,
+ lldb_private::Error &error) override;
+
+ size_t CalculateNumChildren(const StructuredData::ObjectSP &implementor) override;
+
+ lldb::ValueObjectSP GetChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx) override;
+
+ int GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor, const char *child_name) override;
+
+ bool UpdateSynthProviderInstance(const StructuredData::ObjectSP &implementor) override;
+
+ bool MightHaveChildrenSynthProviderInstance(const StructuredData::ObjectSP &implementor) override;
+
+ lldb::ValueObjectSP GetSyntheticValue(const StructuredData::ObjectSP &implementor) override;
- bool
- ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp,
- Event *event,
- bool &script_error) override;
- bool
- ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp,
- Event *event,
- bool &script_error) override;
- lldb::StateType
- ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp,
- bool &script_error) override;
-
- lldb::ScriptInterpreterObjectSP
- OSPlugin_CreatePluginObject (const char *class_name,
- lldb::ProcessSP process_sp) override;
-
- lldb::ScriptInterpreterObjectSP
- OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) override;
-
- lldb::ScriptInterpreterObjectSP
- OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) override;
-
- lldb::ScriptInterpreterObjectSP
- OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
- lldb::tid_t thread_id) override;
-
- lldb::ScriptInterpreterObjectSP
- OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
- lldb::tid_t tid,
- lldb::addr_t context) override;
-
- lldb::ScriptInterpreterObjectSP
- LoadPluginModule (const FileSpec& file_spec,
- lldb_private::Error& error) override;
-
- lldb::ScriptInterpreterObjectSP
- GetDynamicSettings (lldb::ScriptInterpreterObjectSP plugin_module_sp,
- Target* target,
- const char* setting_name,
- lldb_private::Error& error) override;
-
- size_t
- CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor) override;
-
- lldb::ValueObjectSP
- GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor, uint32_t idx) override;
-
- int
- GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor, const char* child_name) override;
-
- bool
- UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor) override;
-
- bool
- MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor) override;
-
- lldb::ValueObjectSP
- GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor) override;
-
bool
RunScriptBasedCommand(const char* impl_function,
const char* args,
@@ -155,6 +217,14 @@ public:
Error& error,
const lldb_private::ExecutionContext& exe_ctx) override;
+ bool
+ RunScriptBasedCommand (StructuredData::GenericSP impl_obj_sp,
+ const char* args,
+ ScriptedCommandSynchronicity synchronicity,
+ lldb_private::CommandReturnObject& cmd_retobj,
+ Error& error,
+ const lldb_private::ExecutionContext& exe_ctx) override;
+
Error
GenerateFunction(const char *signature, const StringList &input) override;
@@ -188,14 +258,10 @@ public:
WatchpointCallbackFunction (void *baton,
StoppointCallbackContext *context,
lldb::user_id_t watch_id);
-
- bool
- GetScriptedSummary (const char *function_name,
- lldb::ValueObjectSP valobj,
- lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
- const TypeSummaryOptions& options,
- std::string& retval) override;
-
+
+ bool GetScriptedSummary(const char *function_name, lldb::ValueObjectSP valobj, StructuredData::ObjectSP &callee_wrapper_sp,
+ const TypeSummaryOptions &options, std::string &retval) override;
+
void
Clear () override;
@@ -203,6 +269,15 @@ public:
GetDocumentationForItem (const char* item, std::string& dest) override;
bool
+ GetShortHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp, std::string& dest) override;
+
+ uint32_t
+ GetFlagsForCommandObject (StructuredData::GenericSP cmd_obj_sp) override;
+
+ bool
+ GetLongHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp, std::string& dest) override;
+
+ bool
CheckObjectExists (const char* name) override
{
if (!name || !name[0])
@@ -240,17 +315,13 @@ public:
ValueObject* value,
std::string& output,
Error& error) override;
-
+
+ bool LoadScriptingModule(const char *filename, bool can_reload, bool init_session, lldb_private::Error &error,
+ StructuredData::ObjectSP *module_sp = nullptr) override;
+
bool
- LoadScriptingModule (const char* filename,
- bool can_reload,
- bool init_session,
- lldb_private::Error& error,
- lldb::ScriptInterpreterObjectSP* module_sp = nullptr) override;
-
- lldb::ScriptInterpreterObjectSP
- MakeScriptObject (void* object) override;
-
+ IsReservedWord (const char* word) override;
+
std::unique_ptr<ScriptInterpreterLocker>
AcquireInterpreterLock () override;
@@ -278,10 +349,9 @@ public:
StringList
ReadCommandInputFromUser (FILE *in_file);
-
- virtual void
- ResetOutputFileHandle (FILE *new_fh) override;
-
+
+ void ResetOutputFileHandle(FILE *new_fh) override;
+
static void
InitializePrivate ();
@@ -291,6 +361,7 @@ public:
SWIGWatchpointCallbackFunction swig_watchpoint_callback,
SWIGPythonTypeScriptCallbackFunction swig_typescript_callback,
SWIGPythonCreateSyntheticProvider swig_synthetic_script,
+ SWIGPythonCreateCommandObject swig_create_cmd,
SWIGPythonCalculateNumChildren swig_calc_children,
SWIGPythonGetChildAtIndex swig_get_child_index,
SWIGPythonGetIndexOfChildWithName swig_get_index_child,
@@ -300,6 +371,7 @@ public:
SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider,
SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider,
SWIGPythonCallCommand swig_call_command,
+ SWIGPythonCallCommandObject swig_call_command_object,
SWIGPythonCallModuleInit swig_call_module_init,
SWIGPythonCreateOSPlugin swig_create_os_plugin,
SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
@@ -369,35 +441,6 @@ protected:
~SynchronicityHandler();
};
- class ScriptInterpreterPythonObject : public ScriptInterpreterObject
- {
- public:
- ScriptInterpreterPythonObject() :
- ScriptInterpreterObject()
- {}
-
- ScriptInterpreterPythonObject(void* obj) :
- ScriptInterpreterObject(obj)
- {
- Py_XINCREF(m_object);
- }
-
- explicit operator bool ()
- {
- return m_object && m_object != Py_None;
- }
-
-
- virtual
- ~ScriptInterpreterPythonObject()
- {
- if (Py_IsInitialized())
- Py_XDECREF(m_object);
- m_object = NULL;
- }
- private:
- DISALLOW_COPY_AND_ASSIGN (ScriptInterpreterPythonObject);
- };
public:
class Locker : public ScriptInterpreterLocker
{
@@ -450,6 +493,13 @@ public:
PyGILState_STATE m_GILState;
};
protected:
+ enum class AddLocation
+ {
+ Beginning,
+ End
+ };
+
+ static void AddToSysPath(AddLocation location, std::string path);
uint32_t
IsExecutingPython () const
diff --git a/include/lldb/Symbol/ClangASTContext.h b/include/lldb/Symbol/ClangASTContext.h
index a9096fe66151..a411e42fe0c5 100644
--- a/include/lldb/Symbol/ClangASTContext.h
+++ b/include/lldb/Symbol/ClangASTContext.h
@@ -235,7 +235,7 @@ public:
clang::IdentifierInfo &myIdent = ast->Idents.get(type_name.GetCString());
clang::DeclarationName myName = ast->DeclarationNames.getIdentifier(&myIdent);
- clang::DeclContext::lookup_const_result result = ast->getTranslationUnitDecl()->lookup(myName);
+ clang::DeclContext::lookup_result result = ast->getTranslationUnitDecl()->lookup(myName);
if (!result.empty())
{
diff --git a/include/lldb/Symbol/ClangASTType.h b/include/lldb/Symbol/ClangASTType.h
index 94c768780a00..2524751e092e 100644
--- a/include/lldb/Symbol/ClangASTType.h
+++ b/include/lldb/Symbol/ClangASTType.h
@@ -351,10 +351,10 @@ public:
//----------------------------------------------------------------------
uint64_t
- GetByteSize (ExecutionContext *exe_ctx) const;
+ GetByteSize (ExecutionContextScope *exe_scope) const;
uint64_t
- GetBitSize (ExecutionContext *exe_ctx) const;
+ GetBitSize (ExecutionContextScope *exe_scope) const;
lldb::Encoding
GetEncoding (uint64_t &count) const;
diff --git a/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h b/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h
index 0c8121135ef0..41bb235636f0 100644
--- a/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h
+++ b/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h
@@ -34,13 +34,11 @@ public:
typedef void (*CompleteTagDeclCallback)(void *baton, clang::TagDecl *);
typedef void (*CompleteObjCInterfaceDeclCallback)(void *baton, clang::ObjCInterfaceDecl *);
typedef void (*FindExternalVisibleDeclsByNameCallback)(void *baton, const clang::DeclContext *DC, clang::DeclarationName Name, llvm::SmallVectorImpl <clang::NamedDecl *> *results);
- typedef bool (*LayoutRecordTypeCallback)(void *baton,
- const clang::RecordDecl *Record,
- uint64_t &Size,
- uint64_t &Alignment,
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets);
+ typedef bool (*LayoutRecordTypeCallback)(
+ void *baton, const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets);
ClangExternalASTSourceCallbacks (CompleteTagDeclCallback tag_decl_callback,
CompleteObjCInterfaceDeclCallback objc_decl_callback,
@@ -59,39 +57,39 @@ public:
// clang::ExternalASTSource
//------------------------------------------------------------------
- virtual clang::Decl *
- GetExternalDecl (uint32_t ID)
+ clang::Decl *
+ GetExternalDecl(uint32_t ID) override
{
// This method only needs to be implemented if the AST source ever
// passes back decl sets as VisibleDeclaration objects.
return 0;
}
-
- virtual clang::Stmt *
- GetExternalDeclStmt (uint64_t Offset)
+
+ clang::Stmt *
+ GetExternalDeclStmt(uint64_t Offset) override
{
// This operation is meant to be used via a LazyOffsetPtr. It only
// needs to be implemented if the AST source uses methods like
// FunctionDecl::setLazyBody when building decls.
return 0;
}
-
- virtual clang::Selector
- GetExternalSelector (uint32_t ID)
+
+ clang::Selector
+ GetExternalSelector(uint32_t ID) override
{
// This operation only needs to be implemented if the AST source
// returns non-zero for GetNumKnownSelectors().
return clang::Selector();
}
- virtual uint32_t
- GetNumExternalSelectors()
+ uint32_t
+ GetNumExternalSelectors() override
{
return 0;
}
-
- virtual clang::CXXBaseSpecifier *
- GetExternalCXXBaseSpecifiers(uint64_t Offset)
+
+ clang::CXXBaseSpecifier *
+ GetExternalCXXBaseSpecifiers(uint64_t Offset) override
{
return NULL;
}
@@ -101,34 +99,26 @@ public:
{
return;
}
-
- virtual clang::ExternalLoadResult
- FindExternalLexicalDecls (const clang::DeclContext *decl_ctx,
- bool (*isKindWeWant)(clang::Decl::Kind),
- llvm::SmallVectorImpl<clang::Decl*> &decls)
+
+ clang::ExternalLoadResult
+ FindExternalLexicalDecls(const clang::DeclContext *decl_ctx, bool (*isKindWeWant)(clang::Decl::Kind),
+ llvm::SmallVectorImpl<clang::Decl *> &decls) override
{
// This is used to support iterating through an entire lexical context,
// which isn't something the debugger should ever need to do.
return clang::ELR_Failure;
}
-
- virtual bool
- FindExternalVisibleDeclsByName (const clang::DeclContext *decl_ctx,
- clang::DeclarationName decl_name);
-
- virtual void
- CompleteType (clang::TagDecl *tag_decl);
-
- virtual void
- CompleteType (clang::ObjCInterfaceDecl *objc_decl);
-
- bool
- layoutRecordType(const clang::RecordDecl *Record,
- uint64_t &Size,
- uint64_t &Alignment,
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets);
+
+ bool FindExternalVisibleDeclsByName(const clang::DeclContext *decl_ctx, clang::DeclarationName decl_name) override;
+
+ void CompleteType(clang::TagDecl *tag_decl) override;
+
+ void CompleteType(clang::ObjCInterfaceDecl *objc_decl) override;
+
+ bool layoutRecordType(const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets) override;
void
SetExternalSourceCallbacks (CompleteTagDeclCallback tag_decl_callback,
CompleteObjCInterfaceDeclCallback objc_decl_callback,
diff --git a/include/lldb/Symbol/CompileUnit.h b/include/lldb/Symbol/CompileUnit.h
index f9238ebba18c..e0c069352bf4 100644
--- a/include/lldb/Symbol/CompileUnit.h
+++ b/include/lldb/Symbol/CompileUnit.h
@@ -256,6 +256,18 @@ public:
//------------------------------------------------------------------
FileSpecList&
GetSupportFiles ();
+
+ //------------------------------------------------------------------
+ /// Get the compile unit's imported module list.
+ ///
+ /// This reports all the imports that the compile unit made,
+ /// including the current module.
+ ///
+ /// @return
+ /// A list of imported module names.
+ //------------------------------------------------------------------
+ const std::vector<ConstString> &
+ GetImportedModules ();
//------------------------------------------------------------------
/// Get the SymbolFile plug-in user data.
@@ -400,6 +412,8 @@ protected:
Flags m_flags; ///< Compile unit flags that help with partial parsing.
std::vector<lldb::FunctionSP> m_functions; ///< The sparsely populated list of shared pointers to functions
///< that gets populated as functions get partially parsed.
+ std::vector<ConstString> m_imported_modules; ///< All modules, including the current module, imported by this
+ ///< compile unit.
FileSpecList m_support_files; ///< Files associated with this compile unit's line table and declarations.
std::unique_ptr<LineTable> m_line_table_ap; ///< Line table that will get parsed on demand.
lldb::VariableListSP m_variables; ///< Global and static variable list that will get parsed on demand.
@@ -407,11 +421,12 @@ protected:
private:
enum
{
- flagsParsedAllFunctions = (1u << 0), ///< Have we already parsed all our functions
- flagsParsedVariables = (1u << 1), ///< Have we already parsed globals and statics?
- flagsParsedSupportFiles = (1u << 2), ///< Have we already parsed the support files for this compile unit?
- flagsParsedLineTable = (1u << 3), ///< Have we parsed the line table already?
- flagsParsedLanguage = (1u << 4) ///< Have we parsed the line table already?
+ flagsParsedAllFunctions = (1u << 0), ///< Have we already parsed all our functions
+ flagsParsedVariables = (1u << 1), ///< Have we already parsed globals and statics?
+ flagsParsedSupportFiles = (1u << 2), ///< Have we already parsed the support files for this compile unit?
+ flagsParsedLineTable = (1u << 3), ///< Have we parsed the line table already?
+ flagsParsedLanguage = (1u << 4), ///< Have we parsed the line table already?
+ flagsParsedImportedModules = (1u << 5) ///< Have we parsed the imported modules already?
};
DISALLOW_COPY_AND_ASSIGN (CompileUnit);
diff --git a/include/lldb/Symbol/DWARFCallFrameInfo.h b/include/lldb/Symbol/DWARFCallFrameInfo.h
index 27d1a52b49f8..cc497c039a4e 100644
--- a/include/lldb/Symbol/DWARFCallFrameInfo.h
+++ b/include/lldb/Symbol/DWARFCallFrameInfo.h
@@ -131,6 +131,16 @@ private:
void
GetCFIData();
+ // Applies the specified DWARF opcode to the given row. This function handle the commands
+ // operates only on a single row (these are the ones what can appear both in CIE and in FDE).
+ // Returns true if the opcode is handled and false otherwise.
+ bool
+ HandleCommonDwarfOpcode(uint8_t primary_opcode,
+ uint8_t extended_opcode,
+ int32_t data_align,
+ lldb::offset_t& offset,
+ UnwindPlan::Row& row);
+
ObjectFile& m_objfile;
lldb::SectionSP m_section_sp;
lldb::RegisterKind m_reg_kind;
diff --git a/include/lldb/Symbol/FuncUnwinders.h b/include/lldb/Symbol/FuncUnwinders.h
index 1e579c42acb8..0d4aabb5fd57 100644
--- a/include/lldb/Symbol/FuncUnwinders.h
+++ b/include/lldb/Symbol/FuncUnwinders.h
@@ -50,7 +50,7 @@ public:
GetUnwindPlanAtNonCallSite (Target& target, lldb_private::Thread& thread, int current_offset);
lldb::UnwindPlanSP
- GetUnwindPlanFastUnwind (lldb_private::Thread& Thread);
+ GetUnwindPlanFastUnwind (Target& target, lldb_private::Thread& thread);
lldb::UnwindPlanSP
GetUnwindPlanArchitectureDefault (lldb_private::Thread& thread);
@@ -111,7 +111,7 @@ public:
private:
lldb::UnwindAssemblySP
- GetUnwindAssemblyProfiler ();
+ GetUnwindAssemblyProfiler (Target& target);
UnwindTable& m_unwind_table;
AddressRange m_range;
diff --git a/include/lldb/Symbol/ObjectFile.h b/include/lldb/Symbol/ObjectFile.h
index 8bcf92de42e5..ff00ac26e67e 100644
--- a/include/lldb/Symbol/ObjectFile.h
+++ b/include/lldb/Symbol/ObjectFile.h
@@ -836,6 +836,13 @@ public:
{
return m_memory_addr != LLDB_INVALID_ADDRESS;
}
+
+ // Strip linker annotations (such as @@VERSION) from symbol names.
+ virtual std::string
+ StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const
+ {
+ return symbol_name.str();
+ }
protected:
//------------------------------------------------------------------
diff --git a/include/lldb/Symbol/Symbol.h b/include/lldb/Symbol/Symbol.h
index 0dd04b7112bc..ad11563634ea 100644
--- a/include/lldb/Symbol/Symbol.h
+++ b/include/lldb/Symbol/Symbol.h
@@ -39,11 +39,11 @@ public:
lldb::addr_t value,
lldb::addr_t size,
bool size_is_valid,
+ bool contains_linker_annotations,
uint32_t flags);
Symbol (uint32_t symID,
- const char *name,
- bool name_is_mangled,
+ const Mangled &mangled,
lldb::SymbolType type,
bool external,
bool is_debug,
@@ -51,6 +51,7 @@ public:
bool is_artificial,
const AddressRange &range,
bool size_is_valid,
+ bool contains_linker_annotations,
uint32_t flags);
Symbol (const Symbol& rhs);
@@ -71,25 +72,81 @@ public:
ValueIsAddress() const;
//------------------------------------------------------------------
- // Access the address value. Do NOT hand out the AddressRange as an
- // object as the byte size of the address range may not be filled in
- // and it should be accessed via GetByteSize().
+ // The GetAddressRef() accessor functions should only be called if
+ // you previously call ValueIsAddress() otherwise you might get an
+ // reference to an Address object that contains an constant integer
+ // value in m_addr_range.m_base_addr.m_offset which could be
+ // incorrectly used to represent an absolute address since it has
+ // no section.
//------------------------------------------------------------------
Address &
- GetAddress()
+ GetAddressRef()
+ {
+ return m_addr_range.GetBaseAddress();
+ }
+
+ const Address &
+ GetAddressRef() const
{
return m_addr_range.GetBaseAddress();
}
//------------------------------------------------------------------
+ // Makes sure the symbol's value is an address and returns the file
+ // address. Returns LLDB_INVALID_ADDRESS if the symbol's value isn't
+ // an address.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetFileAddress () const;
+
+ //------------------------------------------------------------------
+ // Makes sure the symbol's value is an address and gets the load
+ // address using \a target if it is. Returns LLDB_INVALID_ADDRESS
+ // if the symbol's value isn't an address or if the section isn't
+ // loaded in \a target.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetLoadAddress (Target *target) const;
+
+ //------------------------------------------------------------------
// Access the address value. Do NOT hand out the AddressRange as an
// object as the byte size of the address range may not be filled in
// and it should be accessed via GetByteSize().
//------------------------------------------------------------------
- const Address &
+ Address
GetAddress() const
{
- return m_addr_range.GetBaseAddress();
+ // Make sure the our value is an address before we hand a copy out.
+ // We use the Address inside m_addr_range to contain the value for
+ // symbols that are not address based symbols so we are using it
+ // for more than just addresses. For example undefined symbols on
+ // MacOSX have a nlist.n_value of 0 (zero) and this will get placed
+ // into m_addr_range.m_base_addr.m_offset and it will have no section.
+ // So in the GetAddress() accessor, we need to hand out an invalid
+ // address if the symbol's value isn't an address.
+ if (ValueIsAddress())
+ return m_addr_range.GetBaseAddress();
+ else
+ return Address();
+ }
+
+ // When a symbol's value isn't an address, we need to access the raw
+ // value. This function will ensure this symbol's value isn't an address
+ // and return the integer value if this checks out, otherwise it will
+ // return "fail_value" if the symbol is an address value.
+ uint64_t
+ GetIntegerValue (uint64_t fail_value = 0) const
+ {
+ if (ValueIsAddress())
+ {
+ // This symbol's value is an address. Use Symbol::GetAddress() to get the address.
+ return fail_value;
+ }
+ else
+ {
+ // The value is stored in the base address' offset
+ return m_addr_range.GetBaseAddress().GetOffset();
+ }
}
lldb::addr_t
@@ -131,7 +188,7 @@ public:
FileSpec
GetReExportedSymbolSharedLibrary () const;
- bool
+ void
SetReExportedSymbolName(const ConstString &name);
bool
@@ -272,6 +329,16 @@ public:
m_demangled_is_synthesized = b;
}
+ bool
+ ContainsLinkerAnnotations() const
+ {
+ return m_contains_linker_annotations;
+ }
+ void
+ SetContainsLinkerAnnotations(bool b)
+ {
+ m_contains_linker_annotations = b;
+ }
//------------------------------------------------------------------
/// @copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*)
///
@@ -325,7 +392,8 @@ protected:
m_size_is_synthesized:1,// non-zero if this symbol's size was calculated using a delta between this symbol and the next
m_size_is_valid:1,
m_demangled_is_synthesized:1, // The demangled name was created should not be used for expressions or other lookups
- m_type:8;
+ m_contains_linker_annotations:1, // The symbol name contains linker annotations, which are optional when doing name lookups
+ m_type:7;
Mangled m_mangled; // uniqued symbol name/mangled name pair
AddressRange m_addr_range; // Contains the value, or the section offset address when the value is an address in a section, and the size (if any)
uint32_t m_flags; // A copy of the flags from the original symbol table, the ObjectFile plug-in can interpret these
diff --git a/include/lldb/Symbol/SymbolContext.h b/include/lldb/Symbol/SymbolContext.h
index 64490627b84d..c48505e1064a 100644
--- a/include/lldb/Symbol/SymbolContext.h
+++ b/include/lldb/Symbol/SymbolContext.h
@@ -161,6 +161,32 @@ public:
///
/// @param[in] so_addr
/// The resolved section offset address.
+ ///
+ /// @param[in] show_fullpaths
+ /// When printing file paths (with the Module), whether the
+ /// base name of the Module should be printed or the full path.
+ ///
+ /// @param[in] show_module
+ /// Whether the module name should be printed followed by a
+ /// grave accent "`" character.
+ ///
+ /// @param[in] show_inlined_frames
+ /// If a given pc is in inlined function(s), whether the inlined
+ /// functions should be printed on separate lines in addition to
+ /// the concrete function containing the pc.
+ ///
+ /// @param[in] show_function_arguments
+ /// If false, this method will try to elide the function argument
+ /// types when printing the function name. This may be ambiguous
+ /// for languages that have function overloading - but it may
+ /// make the "function name" too long to include all the argument
+ /// types.
+ ///
+ /// @param[in] show_function_name
+ /// Normally this should be true - the function/symbol name should
+ /// be printed. In disassembly formatting, where we want a format
+ /// like "<*+36>", this should be false and "*" will be printed
+ /// instead.
//------------------------------------------------------------------
bool
DumpStopContext (Stream *s,
@@ -169,7 +195,8 @@ public:
bool show_fullpaths,
bool show_module,
bool show_inlined_frames,
- bool show_function_arguments) const;
+ bool show_function_arguments,
+ bool show_function_name) const;
//------------------------------------------------------------------
/// Get the address range contained within a symbol context.
diff --git a/include/lldb/Symbol/SymbolFile.h b/include/lldb/Symbol/SymbolFile.h
index 6df3d49fc464..0efe034235d5 100644
--- a/include/lldb/Symbol/SymbolFile.h
+++ b/include/lldb/Symbol/SymbolFile.h
@@ -124,6 +124,7 @@ public:
virtual size_t ParseCompileUnitFunctions (const SymbolContext& sc) = 0;
virtual bool ParseCompileUnitLineTable (const SymbolContext& sc) = 0;
virtual bool ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files) = 0;
+ virtual bool ParseImportedModules (const SymbolContext &sc, std::vector<ConstString> &imported_modules) = 0;
virtual size_t ParseFunctionBlocks (const SymbolContext& sc) = 0;
virtual size_t ParseTypes (const SymbolContext& sc) = 0;
virtual size_t ParseVariablesForContext (const SymbolContext& sc) = 0;
diff --git a/include/lldb/Symbol/SymbolVendor.h b/include/lldb/Symbol/SymbolVendor.h
index 82f902d4e07b..248918af2833 100644
--- a/include/lldb/Symbol/SymbolVendor.h
+++ b/include/lldb/Symbol/SymbolVendor.h
@@ -66,6 +66,10 @@ public:
virtual bool
ParseCompileUnitSupportFiles (const SymbolContext& sc,
FileSpecList& support_files);
+
+ virtual bool
+ ParseImportedModules (const SymbolContext &sc,
+ std::vector<ConstString> &imported_modules);
virtual size_t
ParseFunctionBlocks (const SymbolContext& sc);
@@ -164,6 +168,9 @@ public:
return m_sym_file_ap.get();
}
+ FileSpec
+ GetMainFileSpec() const;
+
// Get module unified section list symbol table.
virtual Symtab *
GetSymtab ();
diff --git a/include/lldb/Symbol/Symtab.h b/include/lldb/Symbol/Symtab.h
index dc08333e22fb..cf28c7e87ac5 100644
--- a/include/lldb/Symbol/Symtab.h
+++ b/include/lldb/Symbol/Symtab.h
@@ -58,6 +58,14 @@ public:
Symbol * SymbolAtIndex (size_t idx);
const Symbol * SymbolAtIndex (size_t idx) const;
Symbol * FindSymbolWithType (lldb::SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, uint32_t &start_idx);
+ //----------------------------------------------------------------------
+ /// Get the parent symbol for the given symbol.
+ ///
+ /// Many symbols in symbol tables are scoped by other symbols that
+ /// contain one or more symbol. This function will look for such a
+ /// containing symbol and return it if there is one.
+ //----------------------------------------------------------------------
+ const Symbol * GetParent (Symbol *symbol) const;
uint32_t AppendSymbolIndexesWithType (lldb::SymbolType symbol_type, std::vector<uint32_t>& indexes, uint32_t start_idx = 0, uint32_t end_index = UINT32_MAX) const;
uint32_t AppendSymbolIndexesWithTypeAndFlagsValue (lldb::SymbolType symbol_type, uint32_t flags_value, std::vector<uint32_t>& indexes, uint32_t start_idx = 0, uint32_t end_index = UINT32_MAX) const;
uint32_t AppendSymbolIndexesWithType (lldb::SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& matches, uint32_t start_idx = 0, uint32_t end_index = UINT32_MAX) const;
diff --git a/include/lldb/Symbol/Type.h b/include/lldb/Symbol/Type.h
index 51bd3dd82c92..c1784cb364a8 100644
--- a/include/lldb/Symbol/Type.h
+++ b/include/lldb/Symbol/Type.h
@@ -71,7 +71,12 @@ public:
eEncodingIsSyntheticUID
} EncodingDataType;
- typedef enum ResolveStateTag
+ // We must force the underlying type of the enum to be unsigned here. Not all compilers
+ // behave the same with regards to the default underlying type of an enum, but because
+ // this enum is used in an enum bitfield and integer comparisons are done with the value
+ // we need to guarantee that it's always unsigned so that, for example, eResolveStateFull
+ // doesn't compare less than eResolveStateUnresolved when used in a 2-bit bitfield.
+ typedef enum ResolveStateTag : unsigned
{
eResolveStateUnresolved = 0,
eResolveStateForward = 1,
@@ -300,7 +305,12 @@ protected:
ClangASTType m_clang_type;
struct Flags {
+#ifdef __GNUC__
+ // using unsigned type here to work around a very noisy gcc warning
+ unsigned clang_type_resolve_state : 2;
+#else
ResolveState clang_type_resolve_state : 2;
+#endif
bool is_complete_objc_class : 1;
} m_flags;
diff --git a/include/lldb/Symbol/UnwindPlan.h b/include/lldb/Symbol/UnwindPlan.h
index c482739cb8f6..bfc008a5b6bc 100644
--- a/include/lldb/Symbol/UnwindPlan.h
+++ b/include/lldb/Symbol/UnwindPlan.h
@@ -237,17 +237,178 @@ public:
} m_location;
};
+ class CFAValue
+ {
+ public:
+
+ enum ValueType
+ {
+ unspecified, // not specified
+ isRegisterPlusOffset, // CFA = register + offset
+ isRegisterDereferenced, // CFA = [reg]
+ isDWARFExpression // CFA = eval(dwarf_expr)
+ };
+
+ CFAValue() :
+ m_type(unspecified),
+ m_value()
+ {
+ }
+
+ bool
+ operator == (const CFAValue& rhs) const;
+
+ bool
+ operator != (const CFAValue &rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ void
+ SetUnspecified()
+ {
+ m_type = unspecified;
+ }
+
+ bool
+ IsUnspecified () const
+ {
+ return m_type == unspecified;
+ }
+
+ bool
+ IsRegisterPlusOffset () const
+ {
+ return m_type == isRegisterPlusOffset;
+ }
+
+ void
+ SetIsRegisterPlusOffset (uint32_t reg_num, int32_t offset)
+ {
+ m_type = isRegisterPlusOffset;
+ m_value.reg.reg_num = reg_num;
+ m_value.reg.offset = offset;
+ }
+
+ bool
+ IsRegisterDereferenced () const
+ {
+ return m_type == isRegisterDereferenced;
+ }
+
+ void
+ SetIsRegisterDereferenced (uint32_t reg_num)
+ {
+ m_type = isRegisterDereferenced;
+ m_value.reg.reg_num = reg_num;
+ }
+
+ bool
+ IsDWARFExpression () const
+ {
+ return m_type == isDWARFExpression;
+ }
+
+ void
+ SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
+ {
+ m_type = isDWARFExpression;
+ m_value.expr.opcodes = opcodes;
+ m_value.expr.length = len;
+ }
+
+ uint32_t
+ GetRegisterNumber () const
+ {
+ if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset)
+ return m_value.reg.reg_num;
+ return LLDB_INVALID_REGNUM;
+ }
+
+ ValueType
+ GetValueType () const
+ {
+ return m_type;
+ }
+
+ int32_t
+ GetOffset () const
+ {
+ if (m_type == isRegisterPlusOffset)
+ return m_value.reg.offset;
+ return 0;
+ }
+
+ void IncOffset (int32_t delta)
+ {
+ if (m_type == isRegisterPlusOffset)
+ m_value.reg.offset += delta;
+ }
+
+ void SetOffset (int32_t offset)
+ {
+ if (m_type == isRegisterPlusOffset)
+ m_value.reg.offset = offset;
+ }
+
+ void
+ GetDWARFExpr (const uint8_t **opcodes, uint16_t& len) const
+ {
+ if (m_type == isDWARFExpression)
+ {
+ *opcodes = m_value.expr.opcodes;
+ len = m_value.expr.length;
+ }
+ else
+ {
+ *opcodes = NULL;
+ len = 0;
+ }
+ }
+
+ const uint8_t *
+ GetDWARFExpressionBytes ()
+ {
+ if (m_type == isDWARFExpression)
+ return m_value.expr.opcodes;
+ return NULL;
+ }
+
+ int
+ GetDWARFExpressionLength ()
+ {
+ if (m_type == isDWARFExpression)
+ return m_value.expr.length;
+ return 0;
+ }
+
+ void
+ Dump (Stream &s,
+ const UnwindPlan* unwind_plan,
+ Thread* thread) const;
+
+ private:
+ ValueType m_type; // How do we compute CFA value?
+ union
+ {
+ struct {
+ // For m_type == isRegisterPlusOffset or m_type == isRegisterDereferenced
+ uint32_t reg_num; // The register number
+ // For m_type == isRegisterPlusOffset
+ int32_t offset;
+ } reg;
+ // For m_type == isDWARFExpression
+ struct {
+ const uint8_t *opcodes;
+ uint16_t length;
+ } expr;
+ } m_value;
+ }; // class CFAValue
+
public:
Row ();
-
- Row (const UnwindPlan::Row& rhs) :
- m_offset (rhs.m_offset),
- m_cfa_type (rhs.m_cfa_type),
- m_cfa_reg_num (rhs.m_cfa_reg_num),
- m_cfa_offset (rhs.m_cfa_offset),
- m_register_locations (rhs.m_register_locations)
- {
- }
+
+ Row (const UnwindPlan::Row& rhs) = default;
bool
operator == (const Row &rhs) const;
@@ -279,47 +440,9 @@ public:
m_offset += offset;
}
- // How we can reconstruct the CFA address for this stack frame, at this location
- enum CFAType
- {
- CFAIsRegisterPlusOffset, // the CFA value in a register plus (or minus) an offset
- CFAIsRegisterDereferenced // the address in a register is dereferenced to get CFA value
- };
-
- CFAType
- GetCFAType () const
- {
- return m_cfa_type;
- }
-
- void
- SetCFAType (CFAType cfa_type)
+ CFAValue& GetCFAValue()
{
- m_cfa_type = cfa_type;
- }
-
- // If GetCFAType() is CFAIsRegisterPlusOffset, add GetCFAOffset to the reg value to get CFA value
- // If GetCFAType() is CFAIsRegisterDereferenced, dereference the addr in the reg to get CFA value
- uint32_t
- GetCFARegister () const
- {
- return m_cfa_reg_num;
- }
-
- void
- SetCFARegister (uint32_t reg_num);
-
- // This should not be used when GetCFAType() is CFAIsRegisterDereferenced; will return 0 in that case.
- int32_t
- GetCFAOffset () const
- {
- return m_cfa_offset;
- }
-
- void
- SetCFAOffset (int32_t offset)
- {
- m_cfa_offset = offset;
+ return m_cfa_value;
}
bool
@@ -360,14 +483,7 @@ public:
typedef std::map<uint32_t, RegisterLocation> collection;
lldb::addr_t m_offset; // Offset into the function for this row
- CFAType m_cfa_type;
-
- // If m_cfa_type == CFAIsRegisterPlusOffset, the CFA address is computed as m_cfa_reg_num + m_cfa_offset
- // If m_cfa_type == CFAIsRegisterDereferenced, the CFA address is computed as *(m_cfa_reg_num) - i.e. the
- // address in m_cfa_reg_num is dereferenced and the pointer value read is the CFA addr.
- uint32_t m_cfa_reg_num; // The Call Frame Address register number
- int32_t m_cfa_offset; // The offset from the CFA for this row
-
+ CFAValue m_cfa_value;
collection m_register_locations;
}; // class Row
@@ -388,6 +504,22 @@ public:
{
}
+ // Performs a deep copy of the plan, including all the rows (expensive).
+ UnwindPlan (const UnwindPlan &rhs) :
+ m_plan_valid_address_range (rhs.m_plan_valid_address_range),
+ m_register_kind (rhs.m_register_kind),
+ m_return_addr_register (rhs.m_return_addr_register),
+ m_source_name (rhs.m_source_name),
+ m_plan_is_sourced_from_compiler (rhs.m_plan_is_sourced_from_compiler),
+ m_plan_is_valid_at_all_instruction_locations (rhs.m_plan_is_valid_at_all_instruction_locations),
+ m_lsda_address (rhs.m_lsda_address),
+ m_personality_func_addr (rhs.m_personality_func_addr)
+ {
+ m_row_list.reserve (rhs.m_row_list.size());
+ for (const RowSP &row_sp: rhs.m_row_list)
+ m_row_list.emplace_back (new Row (*row_sp));
+ }
+
~UnwindPlan ()
{
}
@@ -437,7 +569,7 @@ public:
{
if (m_row_list.empty())
return LLDB_INVALID_REGNUM;
- return m_row_list.front()->GetCFARegister();
+ return m_row_list.front()->GetCFAValue().GetRegisterNumber();
}
// This UnwindPlan may not be valid at every address of the function span.
diff --git a/include/lldb/Symbol/Variable.h b/include/lldb/Symbol/Variable.h
index 07295d090ee6..a345bcb8c23a 100644
--- a/include/lldb/Symbol/Variable.h
+++ b/include/lldb/Symbol/Variable.h
@@ -29,7 +29,7 @@ public:
//------------------------------------------------------------------
Variable (lldb::user_id_t uid,
const char *name,
- const char *mangled, // The mangled variable name for variables in namespaces
+ const char *mangled, // The mangled or fully qualified name of the variable.
const lldb::SymbolFileTypeSP &symfile_type_sp,
lldb::ValueType scope,
SymbolContextScope *owner_scope,
diff --git a/include/lldb/Target/CPPLanguageRuntime.h b/include/lldb/Target/CPPLanguageRuntime.h
index 43df9e67add0..3e51453566b3 100644
--- a/include/lldb/Target/CPPLanguageRuntime.h
+++ b/include/lldb/Target/CPPLanguageRuntime.h
@@ -153,6 +153,9 @@ public:
static uint32_t
FindEquivalentNames(ConstString type_name, std::vector<ConstString>& equivalents);
+ virtual size_t
+ GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates) = 0;
+
protected:
//------------------------------------------------------------------
// Classes that inherit from CPPLanguageRuntime can see and modify these
diff --git a/include/lldb/Target/FileAction.h b/include/lldb/Target/FileAction.h
index 4015cbb5ea89..907c4d937beb 100644
--- a/include/lldb/Target/FileAction.h
+++ b/include/lldb/Target/FileAction.h
@@ -11,6 +11,7 @@
#define liblldb_Target_FileAction_h
#include <string>
+#include "lldb/Host/FileSpec.h"
namespace lldb_private
{
@@ -34,7 +35,7 @@ class FileAction
bool Duplicate(int fd, int dup_fd);
- bool Open(int fd, const char *path, bool read, bool write);
+ bool Open(int fd, const FileSpec &file_spec, bool read, bool write);
int
GetFD() const
@@ -54,16 +55,20 @@ class FileAction
return m_arg;
}
- const char *GetPath() const;
+ const char *
+ GetPath() const;
+
+ const FileSpec &
+ GetFileSpec() const;
void
Dump (Stream &stream) 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
+ 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
+ FileSpec m_file_spec; // A file spec to use for opening after fork or posix_spawn
};
} // namespace lldb_private
diff --git a/include/lldb/Target/LanguageRuntime.h b/include/lldb/Target/LanguageRuntime.h
index d5ed81956475..d8e5ada6c96f 100644
--- a/include/lldb/Target/LanguageRuntime.h
+++ b/include/lldb/Target/LanguageRuntime.h
@@ -34,6 +34,9 @@ public:
static LanguageRuntime*
FindPlugin (Process *process, lldb::LanguageType language);
+
+ static void
+ InitializeCommands (CommandObject* parent);
virtual lldb::LanguageType
GetLanguageType () const = 0;
@@ -80,16 +83,27 @@ public:
static lldb::BreakpointSP
CreateExceptionBreakpoint (Target &target,
- lldb::LanguageType language,
+ lldb::LanguageType language,
bool catch_bp,
bool throw_bp,
bool is_internal = false);
-
+
+ static Breakpoint::BreakpointPreconditionSP
+ CreateExceptionPrecondition (lldb::LanguageType language,
+ bool catch_bp,
+ bool throw_bp);
+
static lldb::LanguageType
GetLanguageTypeFromString (const char *string);
static const char *
GetNameForLanguageType (lldb::LanguageType language);
+
+ static void
+ PrintAllLanguages (Stream &s, const char *prefix, const char *suffix);
+
+ static bool
+ LanguageIsCPlusPlus (lldb::LanguageType language);
Process *
GetProcess()
@@ -109,6 +123,18 @@ public:
{
return false;
}
+
+ virtual bool
+ IsRuntimeSupportValue (ValueObject& valobj)
+ {
+ return false;
+ }
+
+ virtual void
+ ModulesDidLoad (const ModuleList &module_list)
+ {
+ return;
+ }
protected:
//------------------------------------------------------------------
diff --git a/include/lldb/Target/Memory.h b/include/lldb/Target/Memory.h
index 568bbcdf2f7c..bf1cc1878784 100644
--- a/include/lldb/Target/Memory.h
+++ b/include/lldb/Target/Memory.h
@@ -52,7 +52,7 @@ namespace lldb_private {
uint32_t
GetMemoryCacheLineSize() const
{
- return m_cache_line_byte_size ;
+ return m_L2_cache_line_byte_size ;
}
void
@@ -61,17 +61,26 @@ namespace lldb_private {
bool
RemoveInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size);
+ // Allow external sources to populate data into the L1 memory cache
+ void
+ AddL1CacheData(lldb::addr_t addr, const void *src, size_t src_len);
+
+ void
+ AddL1CacheData(lldb::addr_t addr, const lldb::DataBufferSP &data_buffer_sp);
+
protected:
typedef std::map<lldb::addr_t, lldb::DataBufferSP> BlockMap;
typedef RangeArray<lldb::addr_t, lldb::addr_t, 4> InvalidRanges;
+ typedef Range<lldb::addr_t, lldb::addr_t> AddrRange;
//------------------------------------------------------------------
// Classes that inherit from MemoryCache can see and modify these
//------------------------------------------------------------------
- Process &m_process;
- uint32_t m_cache_line_byte_size;
Mutex m_mutex;
- BlockMap m_cache;
+ BlockMap m_L1_cache; // A first level memory cache whose chunk sizes vary that will be used only if the memory read fits entirely in a chunk
+ BlockMap m_L2_cache; // A memory cache of fixed size chinks (m_L2_cache_line_byte_size bytes in size each)
InvalidRanges m_invalid_ranges;
+ Process &m_process;
+ uint32_t m_L2_cache_line_byte_size;
private:
DISALLOW_COPY_AND_ASSIGN (MemoryCache);
};
diff --git a/include/lldb/Target/ObjCLanguageRuntime.h b/include/lldb/Target/ObjCLanguageRuntime.h
index 42a391478e3e..88874c767a1b 100644
--- a/include/lldb/Target/ObjCLanguageRuntime.h
+++ b/include/lldb/Target/ObjCLanguageRuntime.h
@@ -26,6 +26,8 @@
#include "lldb/Symbol/Type.h"
#include "lldb/Target/LanguageRuntime.h"
+class CommandObjectObjC_ClassTable_Dump;
+
namespace lldb_private {
class ClangUtilityFunction;
@@ -289,6 +291,48 @@ public:
protected:
std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_ap;
};
+
+ class ObjCExceptionPrecondition : public Breakpoint::BreakpointPrecondition
+ {
+ public:
+ ObjCExceptionPrecondition();
+
+ virtual ~ObjCExceptionPrecondition() {}
+
+ bool EvaluatePrecondition(StoppointCallbackContext &context) override;
+ void DescribePrecondition(Stream &stream, lldb::DescriptionLevel level) override;
+ Error ConfigurePrecondition(Args &args) override;
+
+ protected:
+ void AddClassName(const char *class_name);
+
+ private:
+ std::unordered_set<std::string> m_class_names;
+ };
+
+ class TaggedPointerVendor
+ {
+ public:
+ virtual bool
+ IsPossibleTaggedPointer (lldb::addr_t ptr) = 0;
+
+ virtual ObjCLanguageRuntime::ClassDescriptorSP
+ GetClassDescriptor (lldb::addr_t ptr) = 0;
+
+ virtual
+ ~TaggedPointerVendor () { }
+ protected:
+ TaggedPointerVendor () = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendor);
+ };
+
+ virtual TaggedPointerVendor*
+ GetTaggedPointerVendor ()
+ {
+ return nullptr;
+ }
typedef std::shared_ptr<EncodingToType> EncodingToTypeSP;
@@ -313,8 +357,8 @@ public:
virtual
~ObjCLanguageRuntime();
- virtual lldb::LanguageType
- GetLanguageType () const
+ lldb::LanguageType
+ GetLanguageType () const override
{
return lldb::eLanguageTypeObjC;
}
@@ -515,10 +559,10 @@ public:
m_negative_complete_class_cache.clear();
}
- virtual bool
+ bool
GetTypeBitSize (const ClangASTType& clang_type,
- uint64_t &size);
-
+ uint64_t &size) override;
+
protected:
//------------------------------------------------------------------
// Classes that inherit from ObjCLanguageRuntime can see and modify these
@@ -645,6 +689,14 @@ protected:
ISAToDescriptorIterator
GetDescriptorIterator (const ConstString &name);
+ friend class ::CommandObjectObjC_ClassTable_Dump;
+
+ std::pair<ISAToDescriptorIterator,ISAToDescriptorIterator>
+ GetDescriptorIteratorPair (bool update_if_needed = true);
+
+ void
+ ReadObjCLibraryIfNeeded (const ModuleList &module_list);
+
DISALLOW_COPY_AND_ASSIGN (ObjCLanguageRuntime);
};
diff --git a/include/lldb/Target/Platform.h b/include/lldb/Target/Platform.h
index f4596bd00f0b..8f89e9b3cf5f 100644
--- a/include/lldb/Target/Platform.h
+++ b/include/lldb/Target/Platform.h
@@ -12,7 +12,9 @@
// C Includes
// C++ Includes
+#include <functional>
#include <map>
+#include <memory>
#include <string>
#include <vector>
@@ -23,7 +25,9 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/UserSettingsController.h"
#include "lldb/Interpreter/Options.h"
+#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Mutex.h"
// TODO pull NativeDelegate class out of NativeProcessProtocol so we
@@ -32,6 +36,34 @@
namespace lldb_private {
+class ModuleCache;
+
+ enum MmapFlags {
+ eMmapFlagsPrivate = 1,
+ eMmapFlagsAnon = 2
+ };
+
+ class PlatformProperties : public Properties
+ {
+ public:
+ static ConstString
+ GetSettingName ();
+
+ PlatformProperties();
+
+ bool
+ GetUseModuleCache () const;
+ bool
+ SetUseModuleCache (bool use_module_cache);
+
+ FileSpec
+ GetModuleCacheDirectory () const;
+ bool
+ SetModuleCacheDirectory (const FileSpec& dir_spec);
+ };
+
+ typedef std::shared_ptr<PlatformProperties> PlatformPropertiesSP;
+
//----------------------------------------------------------------------
/// @class Platform Platform.h "lldb/Target/Platform.h"
/// @brief A plug-in interface definition class for debug platform that
@@ -49,9 +81,17 @@ namespace lldb_private {
public PluginInterface
{
public:
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static const PlatformPropertiesSP &
+ GetGlobalPlatformProperties ();
//------------------------------------------------------------------
- /// Get the native host platform plug-in.
+ /// Get the native host platform plug-in.
///
/// There should only be one of these for each host that LLDB runs
/// upon that should be statically compiled in and registered using
@@ -277,15 +317,15 @@ namespace lldb_private {
{
return ArchSpec(); // Return an invalid architecture
}
-
- virtual ConstString
+
+ virtual FileSpec
GetRemoteWorkingDirectory()
{
return m_working_dir;
}
virtual bool
- SetRemoteWorkingDirectory(const ConstString &path);
+ SetRemoteWorkingDirectory(const FileSpec &working_dir);
virtual const char *
GetUserName (uint32_t uid);
@@ -336,14 +376,20 @@ namespace lldb_private {
LocateExecutableScriptingResources (Target *target,
Module &module,
Stream* feedback_stream);
-
+
virtual Error
- GetSharedModule (const ModuleSpec &module_spec,
+ GetSharedModule (const ModuleSpec &module_spec,
+ Process* process,
lldb::ModuleSP &module_sp,
const FileSpecList *module_search_paths_ptr,
lldb::ModuleSP *old_module_sp_ptr,
bool *did_create_ptr);
+ virtual bool
+ GetModuleSpec (const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec);
+
virtual Error
ConnectRemote (Args& args);
@@ -380,6 +426,16 @@ namespace lldb_private {
LaunchProcess (ProcessLaunchInfo &launch_info);
//------------------------------------------------------------------
+ /// Perform expansion of the command-line for this launch info
+ /// This can potentially involve wildcard expansion
+ // environment variable replacement, and whatever other
+ // argument magic the platform defines as part of its typical
+ // user experience
+ //------------------------------------------------------------------
+ virtual Error
+ ShellExpandArguments (ProcessLaunchInfo &launch_info);
+
+ //------------------------------------------------------------------
/// Kill process on a platform.
//------------------------------------------------------------------
virtual Error
@@ -577,12 +633,12 @@ namespace lldb_private {
virtual void
AddClangModuleCompilationOptions (Target *target, std::vector<std::string> &options);
- ConstString
- GetWorkingDirectory ();
-
+ FileSpec
+ GetWorkingDirectory();
+
bool
- SetWorkingDirectory (const ConstString &path);
-
+ SetWorkingDirectory(const FileSpec &working_dir);
+
// There may be modules that we don't want to find by default for operations like "setting breakpoint by name".
// The platform will return "true" from this call if the passed in module happens to be one of these.
@@ -593,13 +649,13 @@ namespace lldb_private {
}
virtual Error
- MakeDirectory (const char *path, uint32_t permissions);
-
+ MakeDirectory(const FileSpec &file_spec, uint32_t permissions);
+
virtual Error
- GetFilePermissions (const char *path, uint32_t &file_permissions);
+ GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions);
virtual Error
- SetFilePermissions (const char *path, uint32_t file_permissions);
+ SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions);
virtual lldb::user_id_t
OpenFile (const FileSpec& file_spec,
@@ -656,8 +712,8 @@ namespace lldb_private {
uint32_t gid = UINT32_MAX);
virtual Error
- CreateSymlink (const char *src, // The name of the link is in src
- const char *dst);// The symlink points to dst
+ CreateSymlink(const FileSpec &src, // The name of the link is in src
+ const FileSpec &dst); // The symlink points to dst
//----------------------------------------------------------------------
/// Install a file or directory to the remote system.
@@ -693,7 +749,10 @@ namespace lldb_private {
GetFileExists (const lldb_private::FileSpec& file_spec);
virtual Error
- Unlink (const char *path);
+ Unlink(const FileSpec &file_spec);
+
+ virtual uint64_t
+ ConvertMmapFlagsToPlatform(const ArchSpec &arch, unsigned flags);
virtual bool
GetSupportsRSync ()
@@ -774,13 +833,13 @@ namespace lldb_private {
}
virtual lldb_private::Error
- RunShellCommand (const char *command, // Shouldn't be NULL
- const char *working_dir, // Pass NULL to use the current working directory
- int *status_ptr, // Pass NULL if you don't want the process exit status
- int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
- std::string *command_output, // Pass NULL if you don't want the command output
- uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish
-
+ RunShellCommand(const char *command, // Shouldn't be NULL
+ const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish
+
virtual void
SetLocalCacheDirectory (const char* local);
@@ -950,7 +1009,7 @@ namespace lldb_private {
bool m_system_arch_set_while_connected;
ConstString m_sdk_sysroot; // the root location of where the SDK files are all located
ConstString m_sdk_build;
- ConstString m_working_dir; // The working directory which is used when installing modules that have no install path set
+ FileSpec m_working_dir; // The working directory which is used when installing modules that have no install path set
std::string m_remote_url;
std::string m_name;
uint32_t m_major_os_version;
@@ -972,6 +1031,7 @@ namespace lldb_private {
std::string m_local_cache_directory;
std::vector<ConstString> m_trap_handlers;
bool m_calculated_trap_handlers;
+ const std::unique_ptr<ModuleCache> m_module_cache;
//------------------------------------------------------------------
/// Ask the Platform subclass to fill in the list of trap handler names
@@ -1074,7 +1134,45 @@ namespace lldb_private {
m_gid_map.clear();
}
+ Error
+ GetCachedExecutable (ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ Platform &remote_platform);
+
+ virtual Error
+ DownloadModuleSlice (const FileSpec& src_file_spec,
+ const uint64_t src_offset,
+ const uint64_t src_size,
+ const FileSpec& dst_file_spec);
+
+ virtual const char *
+ GetCacheHostname ();
+
private:
+ typedef std::function<Error (const ModuleSpec &)> ModuleResolver;
+
+ Error
+ GetRemoteSharedModule (const ModuleSpec &module_spec,
+ Process* process,
+ lldb::ModuleSP &module_sp,
+ const ModuleResolver &module_resolver,
+ bool *did_create_ptr);
+
+ bool
+ GetCachedSharedModule (const ModuleSpec& module_spec,
+ lldb::ModuleSP &module_sp,
+ bool *did_create_ptr);
+
+ Error
+ LoadCachedExecutable (const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ Platform &remote_platform);
+
+ FileSpec
+ GetModuleCacheRoot ();
+
DISALLOW_COPY_AND_ASSIGN (Platform);
};
diff --git a/include/lldb/Target/Process.h b/include/lldb/Target/Process.h
index 6608391b94fd..db0f0cfa028b 100644
--- a/include/lldb/Target/Process.h
+++ b/include/lldb/Target/Process.h
@@ -28,34 +28,26 @@
#include "lldb/Core/Communication.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Event.h"
-#include "lldb/Core/RangeMap.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Core/ThreadSafeValue.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Breakpoint/BreakpointSiteList.h"
-#include "lldb/Expression/ClangPersistentVariables.h"
-#include "lldb/Expression/IRDynamicChecks.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/Host.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/ProcessRunLock.h"
-#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"
-#include "lldb/Utility/PseudoTerminal.h"
#include "lldb/Target/InstrumentationRuntime.h"
namespace lldb_private {
+template <typename B, typename S>
+struct Range;
+
//----------------------------------------------------------------------
// ProcessProperties
//----------------------------------------------------------------------
@@ -693,7 +685,20 @@ public:
else
m_running_user_expression--;
}
-
+
+ void
+ SetStopEventForLastNaturalStopID (lldb::EventSP event_sp)
+ {
+ m_last_natural_stop_event = event_sp;
+ }
+
+ lldb::EventSP GetStopEventForStopID (uint32_t stop_id) const
+ {
+ if (stop_id == m_last_natural_stop_id)
+ return m_last_natural_stop_event;
+ return lldb::EventSP();
+ }
+
private:
uint32_t m_stop_id;
uint32_t m_last_natural_stop_id;
@@ -701,6 +706,7 @@ private:
uint32_t m_memory_id;
uint32_t m_last_user_expression_resume;
uint32_t m_running_user_expression;
+ lldb::EventSP m_last_natural_stop_event;
};
inline bool operator== (const ProcessModID &lhs, const ProcessModID &rhs)
{
@@ -812,11 +818,12 @@ public:
virtual const ConstString &
GetFlavor () const;
- const lldb::ProcessSP &
+ lldb::ProcessSP
GetProcessSP() const
{
- return m_process_sp;
+ return m_process_wp.lock();
}
+
lldb::StateType
GetState() const
{
@@ -911,7 +918,7 @@ public:
m_restarted_reasons.push_back(reason);
}
- lldb::ProcessSP m_process_sp;
+ lldb::ProcessWP m_process_wp;
lldb::StateType m_state;
std::vector<std::string> m_restarted_reasons;
bool m_restarted; // For "eStateStopped" events, this is true if the target was automatically restarted.
@@ -1129,6 +1136,22 @@ public:
virtual const lldb::DataBufferSP
GetAuxvData();
+ //------------------------------------------------------------------
+ /// Sometimes processes know how to retrieve and load shared libraries.
+ /// This is normally done by DynamicLoader plug-ins, but sometimes the
+ /// connection to the process allows retrieving this information. The
+ /// dynamic loader plug-ins can use this function if they can't
+ /// determine the current shared library load state.
+ ///
+ /// @return
+ /// The number of shared libraries that were loaded
+ //------------------------------------------------------------------
+ virtual size_t
+ LoadModules ()
+ {
+ return 0;
+ }
+
protected:
virtual JITLoaderList &
GetJITLoaders ();
@@ -1351,11 +1374,19 @@ public:
/// This function is not meant to be overridden by Process
/// subclasses.
///
+ /// @param[in] force_kill
+ /// Whether lldb should force a kill (instead of a detach) from
+ /// the inferior process. Normally if lldb launched a binary and
+ /// Destory is called, lldb kills it. If lldb attached to a
+ /// running process and Destory is called, lldb detaches. If
+ /// this behavior needs to be over-ridden, this is the bool that
+ /// can be used.
+ ///
/// @return
/// Returns an error object.
//------------------------------------------------------------------
Error
- Destroy();
+ Destroy(bool force_kill);
//------------------------------------------------------------------
/// Sends a process a UNIX signal \a signal.
@@ -1370,18 +1401,10 @@ public:
Signal (int signal);
void
- SetUnixSignals (const UnixSignalsSP &signals_sp)
- {
- assert (signals_sp && "null signals_sp");
- m_unix_signals_sp = signals_sp;
- }
+ SetUnixSignals (const UnixSignalsSP &signals_sp);
UnixSignals &
- GetUnixSignals ()
- {
- assert (m_unix_signals_sp && "null m_unix_signals_sp");
- return *m_unix_signals_sp;
- }
+ GetUnixSignals ();
//==================================================================
// Plug-in Process Control Overrides
@@ -1445,31 +1468,14 @@ public:
/// @param[in] pid
/// The process ID that we should attempt to attach to.
///
- /// @return
- /// Returns \a pid if attaching was successful, or
- /// LLDB_INVALID_PROCESS_ID if attaching fails.
- //------------------------------------------------------------------
- virtual Error
- DoAttachToProcessWithID (lldb::pid_t pid)
- {
- Error error;
- error.SetErrorStringWithFormat("error: %s does not support attaching to a process by pid", GetPluginName().GetCString());
- return error;
- }
-
- //------------------------------------------------------------------
- /// Attach to an existing process using a process ID.
- ///
- /// @param[in] pid
- /// The process ID that we should attempt to attach to.
- ///
/// @param[in] attach_info
/// Information on how to do the attach. For example, GetUserID()
/// will return the uid to attach as.
///
/// @return
- /// Returns \a pid if attaching was successful, or
- /// LLDB_INVALID_PROCESS_ID if attaching fails.
+ /// Returns a successful Error attaching was successful, or
+ /// an appropriate (possibly platform-specific) error code if
+ /// attaching fails.
/// hanming : need flag
//------------------------------------------------------------------
virtual Error
@@ -1491,7 +1497,9 @@ public:
/// will return the uid to attach as.
///
/// @return
- /// Returns an error object.
+ /// Returns a successful Error attaching was successful, or
+ /// an appropriate (possibly platform-specific) error code if
+ /// attaching fails.
//------------------------------------------------------------------
virtual Error
DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info)
@@ -1870,7 +1878,13 @@ public:
void
SendAsyncInterrupt ();
- void
+ //------------------------------------------------------------------
+ // Notify this process class that modules got loaded.
+ //
+ // If subclasses override this method, they must call this version
+ // before doing anything in the subclass version of the function.
+ //------------------------------------------------------------------
+ virtual void
ModulesDidLoad (ModuleList &module_list);
protected:
@@ -1961,11 +1975,17 @@ public:
}
uint32_t
- GetLastNaturalStopID()
+ GetLastNaturalStopID() const
{
return m_mod_id.GetLastNaturalStopID();
}
-
+
+ lldb::EventSP
+ GetStopEventForStopID (uint32_t stop_id) const
+ {
+ return m_mod_id.GetStopEventForStopID(stop_id);
+ }
+
//------------------------------------------------------------------
/// Set accessor for the process exit status (return code).
///
@@ -2399,33 +2419,8 @@ public:
/// Returns true if it was able to determine the attributes of the
/// memory region. False if not.
//------------------------------------------------------------------
-
virtual bool
- GetLoadAddressPermissions (lldb::addr_t load_addr, uint32_t &permissions)
- {
- MemoryRegionInfo range_info;
- permissions = 0;
- Error error (GetMemoryRegionInfo (load_addr, range_info));
- if (!error.Success())
- return false;
- if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow
- || range_info.GetWritable() == MemoryRegionInfo::eDontKnow
- || range_info.GetExecutable() == MemoryRegionInfo::eDontKnow)
- {
- return false;
- }
-
- if (range_info.GetReadable() == MemoryRegionInfo::eYes)
- permissions |= lldb::ePermissionsReadable;
-
- if (range_info.GetWritable() == MemoryRegionInfo::eYes)
- permissions |= lldb::ePermissionsWritable;
-
- if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
- permissions |= lldb::ePermissionsExecutable;
-
- return true;
- }
+ GetLoadAddressPermissions (lldb::addr_t load_addr, uint32_t &permissions);
//------------------------------------------------------------------
/// Determines whether executing JIT-compiled code in this process
@@ -2758,6 +2753,11 @@ public:
Listener *hijack_listener = NULL,
Stream *stream = NULL);
+ uint32_t
+ GetIOHandlerID () const
+ {
+ return m_iohandler_sync.GetValue();
+ }
//--------------------------------------------------------------------------------------
/// Waits for the process state to be running within a given msec timeout.
@@ -2768,14 +2768,9 @@ public:
/// @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);
-
+ void
+ SyncIOHandler (uint32_t iohandler_id, uint64_t timeout_msec);
lldb::StateType
WaitForStateChangedEvents (const TimeValue *timeout,
@@ -2906,10 +2901,7 @@ public:
return m_dynamic_checkers_ap.get();
}
- void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers)
- {
- m_dynamic_checkers_ap.reset(dynamic_checkers);
- }
+ void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers);
//------------------------------------------------------------------
/// Call this to set the lldb in the mode where it breaks on new thread
@@ -3010,17 +3002,10 @@ public:
void
ClearPreResumeActions ();
-
+
ProcessRunLock &
- GetRunLock ()
- {
- if (m_private_state_thread.EqualsThread(Host::GetCurrentThread()))
- return m_private_run_lock;
- else
- return m_public_run_lock;
- }
+ GetRunLock ();
-public:
virtual Error
SendEventData(const char *data)
{
@@ -3034,6 +3019,51 @@ public:
lldb::InstrumentationRuntimeSP
GetInstrumentationRuntime(lldb::InstrumentationRuntimeType type);
+ //------------------------------------------------------------------
+ /// Try to fetch the module specification for a module with the
+ /// given file name and architecture. Process sub-classes have to
+ /// override this method if they support platforms where the
+ /// Platform object can't get the module spec for all module.
+ ///
+ /// @param[in] module_file_spec
+ /// The file name of the module to get specification for.
+ ///
+ /// @param[in] arch
+ /// The architecture of the module to get specification for.
+ ///
+ /// @param[out] module_spec
+ /// The fetched module specification if the return value is
+ /// \b true, unchanged otherwise.
+ ///
+ /// @return
+ /// Returns \b true if the module spec fetched successfully,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ GetModuleSpec(const FileSpec& module_file_spec, const ArchSpec& arch, ModuleSpec &module_spec);
+
+ //------------------------------------------------------------------
+ /// Try to find the load address of a file.
+ /// The load address is defined as the address of the first memory
+ /// region what contains data mapped from the specified file.
+ ///
+ /// @param[in] file
+ /// The name of the file whose load address we are looking for
+ ///
+ /// @param[out] is_loaded
+ /// \b True if the file is loaded into the memory and false
+ /// otherwise.
+ ///
+ /// @param[out] load_addr
+ /// The load address of the file if it is loaded into the
+ /// processes address space, LLDB_INVALID_ADDRESS otherwise.
+ //------------------------------------------------------------------
+ virtual Error
+ GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr)
+ {
+ return Error("Not supported");
+ }
+
protected:
//------------------------------------------------------------------
@@ -3150,7 +3180,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.
- HostThread m_private_state_thread; // Thread ID for the thread that watches internal state events
+ HostThread 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.
@@ -3170,22 +3200,22 @@ protected:
std::vector<lldb::addr_t> m_image_tokens;
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;
+ lldb::DynamicLoaderUP m_dyld_ap;
+ lldb::JITLoaderListUP m_jit_loaders_ap;
+ lldb::DynamicCheckerFunctionsUP m_dynamic_checkers_ap; ///< The functions used by the expression parser to validate data that expressions use.
+ lldb::OperatingSystemUP m_os_ap;
+ lldb::SystemRuntimeUP m_system_runtime_ap;
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;
Mutex m_stdio_communication_mutex;
- bool m_stdio_disable; /// Remember process launch setting
+ bool m_stdin_forward; /// Remember if stdin must be forwarded to remote debug server
std::string m_stdout_data;
std::string m_stderr_data;
Mutex m_profile_data_comm_mutex;
std::vector<std::string> m_profile_data;
- Predicate<bool> m_iohandler_sync;
+ Predicate<uint32_t> 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?
@@ -3199,7 +3229,8 @@ protected:
ArchSpec::StopInfoOverrideCallbackType m_stop_info_override_callback;
bool m_currently_handling_do_on_removals;
bool m_resume_requested; // If m_currently_handling_event or m_currently_handling_do_on_removals are true, Resume will only request a resume, using this flag to check.
- bool m_finalize_called;
+ bool m_finalizing; // This is set at the beginning of Process::Finalize() to stop functions from looking up or creating things during a finalize call
+ bool m_finalize_called; // This is set at the end of Process::Finalize()
bool m_clear_thread_plans_on_stop;
bool m_force_next_event_delivery;
lldb::StateType m_last_broadcast_state; /// This helps with the Public event coalescing in ShouldBroadcastEvent.
@@ -3225,7 +3256,7 @@ protected:
SetPrivateState (lldb::StateType state);
bool
- StartPrivateStateThread (bool force = false);
+ StartPrivateStateThread (bool is_secondary_thread = false);
void
StopPrivateStateThread ();
@@ -3236,11 +3267,22 @@ protected:
void
ResumePrivateStateThread ();
+ struct PrivateStateThreadArgs
+ {
+ Process *process;
+ bool is_secondary_thread;
+ };
+
static lldb::thread_result_t
PrivateStateThread (void *arg);
+ // The starts up the private state thread that will watch for events from the debugee.
+ // Pass true for is_secondary_thread in the case where you have to temporarily spin up a
+ // secondary state thread to handle events from a hand-called function on the primary
+ // private state thread.
+
lldb::thread_result_t
- RunPrivateStateThread ();
+ RunPrivateStateThread (bool is_secondary_thread);
void
HandlePrivateEvent (lldb::EventSP &event_sp);
@@ -3285,6 +3327,12 @@ protected:
bool
ProcessIOHandlerIsActive ();
+
+ bool
+ ProcessIOHandlerExists () const
+ {
+ return static_cast<bool>(m_process_input_reader);
+ }
Error
HaltForDestroyOrDetach(lldb::EventSP &exit_event_sp);
diff --git a/include/lldb/Target/ProcessInfo.h b/include/lldb/Target/ProcessInfo.h
index 0570cfc98651..1539e043d6fc 100644
--- a/include/lldb/Target/ProcessInfo.h
+++ b/include/lldb/Target/ProcessInfo.h
@@ -107,7 +107,7 @@ namespace lldb_private
}
void
- SetArchitecture (ArchSpec arch)
+ SetArchitecture (const ArchSpec& arch)
{
m_arch = arch;
}
diff --git a/include/lldb/Target/ProcessLaunchInfo.h b/include/lldb/Target/ProcessLaunchInfo.h
index 897704488e5f..92a3ed40736d 100644
--- a/include/lldb/Target/ProcessLaunchInfo.h
+++ b/include/lldb/Target/ProcessLaunchInfo.h
@@ -36,11 +36,11 @@ namespace lldb_private
ProcessLaunchInfo ();
- ProcessLaunchInfo (const char *stdin_path,
- const char *stdout_path,
- const char *stderr_path,
- const char *working_directory,
- uint32_t launch_flags);
+ ProcessLaunchInfo(const FileSpec &stdin_file_spec,
+ const FileSpec &stdout_file_spec,
+ const FileSpec &stderr_file_spec,
+ const FileSpec &working_dir,
+ uint32_t launch_flags);
void
AppendFileAction (const FileAction &info)
@@ -55,7 +55,8 @@ namespace lldb_private
AppendDuplicateFileAction (int fd, int dup_fd);
bool
- AppendOpenFileAction (int fd, const char *path, bool read, bool write);
+ AppendOpenFileAction(int fd, const FileSpec &file_spec,
+ bool read, bool write);
bool
AppendSuppressFileAction (int fd, bool read, bool write);
@@ -88,17 +89,11 @@ namespace lldb_private
return m_flags;
}
- const char *
- GetWorkingDirectory () const;
-
- void
- SetWorkingDirectory (const char *working_dir);
+ const FileSpec &
+ GetWorkingDirectory() const;
void
- SwapWorkingDirectory (std::string &working_dir)
- {
- m_working_dir.swap (working_dir);
- }
+ SetWorkingDirectory(const FileSpec &working_dir);
const char *
GetProcessPluginName () const;
@@ -132,6 +127,15 @@ namespace lldb_private
void
SetLaunchInSeparateProcessGroup (bool separate);
+
+ bool
+ GetShellExpandArguments () const
+ {
+ return m_flags.Test(lldb::eLaunchFlagShellExpandArguments);
+ }
+
+ void
+ SetShellExpandArguments (bool expand);
void
Clear ();
@@ -229,7 +233,7 @@ namespace lldb_private
}
protected:
- std::string m_working_dir;
+ FileSpec m_working_dir;
std::string m_plugin_name;
FileSpec m_shell;
Flags m_flags; // Bitwise OR of bits from lldb::LaunchFlags
diff --git a/include/lldb/Target/SectionLoadHistory.h b/include/lldb/Target/SectionLoadHistory.h
index 50dcfd3cc870..ddf46a1861ca 100644
--- a/include/lldb/Target/SectionLoadHistory.h
+++ b/include/lldb/Target/SectionLoadHistory.h
@@ -23,7 +23,7 @@ namespace lldb_private {
class SectionLoadHistory
{
public:
- enum {
+ enum : unsigned {
// Pass eStopIDNow to any function that takes a stop ID to get
// the current value.
eStopIDNow = UINT32_MAX
diff --git a/include/lldb/Target/StopInfo.h b/include/lldb/Target/StopInfo.h
index e0d029bcc956..d09900f7637d 100644
--- a/include/lldb/Target/StopInfo.h
+++ b/include/lldb/Target/StopInfo.h
@@ -116,6 +116,12 @@ public:
else
m_description.clear();
}
+
+ virtual bool
+ IsValidForOperatingSystemThread (Thread &thread)
+ {
+ return true;
+ }
// Sometimes the thread plan logic will know that it wants a given stop to stop or not,
// regardless of what the ordinary logic for that StopInfo would dictate. The main example
@@ -158,7 +164,7 @@ public:
CreateStopReasonWithWatchpointID (Thread &thread, lldb::break_id_t watch_id);
static lldb::StopInfoSP
- CreateStopReasonWithSignal (Thread &thread, int signo);
+ CreateStopReasonWithSignal (Thread &thread, int signo, const char *description = nullptr);
static lldb::StopInfoSP
CreateStopReasonToTrace (Thread &thread);
diff --git a/include/lldb/Target/Target.h b/include/lldb/Target/Target.h
index a33734fd5b63..427f68e4c5d4 100644
--- a/include/lldb/Target/Target.h
+++ b/include/lldb/Target/Target.h
@@ -18,24 +18,15 @@
// Project includes
#include "lldb/lldb-public.h"
#include "lldb/Breakpoint/BreakpointList.h"
-#include "lldb/Breakpoint/BreakpointLocationCollection.h"
#include "lldb/Breakpoint/WatchpointList.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Disassembler.h"
-#include "lldb/Core/Event.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/UserSettingsController.h"
-#include "lldb/Expression/ClangModulesDeclVendor.h"
-#include "lldb/Expression/ClangPersistentVariables.h"
-#include "lldb/Interpreter/Args.h"
-#include "lldb/Interpreter/OptionValueBoolean.h"
-#include "lldb/Interpreter/OptionValueEnumeration.h"
-#include "lldb/Interpreter/OptionValueFileSpec.h"
-#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/PathMappingList.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/SectionLoadHistory.h"
namespace lldb_private {
@@ -73,9 +64,15 @@ public:
void
SetDefaultArchitecture (const ArchSpec& arch);
+ bool
+ GetMoveToNearestCode () const;
+
lldb::DynamicValueType
GetPreferDynamicValue() const;
-
+
+ bool
+ SetPreferDynamicValue (lldb::DynamicValueType d);
+
bool
GetDisableASLR () const;
@@ -117,7 +114,10 @@ public:
size_t
GetEnvironmentAsArgs (Args &env) const;
-
+
+ void
+ SetEnvironmentFromArgs (const Args &env);
+
bool
GetSkipPrologue() const;
@@ -130,6 +130,12 @@ public:
FileSpecList &
GetDebugFileSearchPaths ();
+ FileSpecList &
+ GetClangModuleSearchPaths ();
+
+ bool
+ GetEnableAutoImportClangModules () const;
+
bool
GetEnableSyntheticValue () const;
@@ -189,9 +195,46 @@ public:
void
SetUserSpecifiedTrapHandlerNames (const Args &args);
-};
-typedef std::shared_ptr<TargetProperties> TargetPropertiesSP;
+ bool
+ GetNonStopModeEnabled () const;
+
+ void
+ SetNonStopModeEnabled (bool b);
+
+ bool
+ GetDisplayRuntimeSupportValues () const;
+
+ void
+ SetDisplayRuntimeSupportValues (bool b);
+
+ const ProcessLaunchInfo &
+ GetProcessLaunchInfo();
+
+ void
+ SetProcessLaunchInfo(const ProcessLaunchInfo &launch_info);
+
+private:
+ //------------------------------------------------------------------
+ // Callbacks for m_launch_info.
+ //------------------------------------------------------------------
+ static void Arg0ValueChangedCallback(void *target_property_ptr, OptionValue *);
+ static void RunArgsValueChangedCallback(void *target_property_ptr, OptionValue *);
+ static void EnvVarsValueChangedCallback(void *target_property_ptr, OptionValue *);
+ static void InheritEnvValueChangedCallback(void *target_property_ptr, OptionValue *);
+ static void InputPathValueChangedCallback(void *target_property_ptr, OptionValue *);
+ static void OutputPathValueChangedCallback(void *target_property_ptr, OptionValue *);
+ static void ErrorPathValueChangedCallback(void *target_property_ptr, OptionValue *);
+ static void DetachOnErrorValueChangedCallback(void *target_property_ptr, OptionValue *);
+ static void DisableASLRValueChangedCallback(void *target_property_ptr, OptionValue *);
+ static void DisableSTDIOValueChangedCallback(void *target_property_ptr, OptionValue *);
+
+private:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ ProcessLaunchInfo m_launch_info;
+};
class EvaluateExpressionOptions
{
@@ -200,19 +243,20 @@ public:
EvaluateExpressionOptions() :
m_execution_policy(eExecutionPolicyOnlyWhenNeeded),
m_language (lldb::eLanguageTypeUnknown),
- m_coerce_to_id(false),
- m_unwind_on_error(true),
+ m_prefix (), // A prefix specific to this expression that is added after the prefix from the settings (if any)
+ m_coerce_to_id (false),
+ m_unwind_on_error (true),
m_ignore_breakpoints (false),
- m_keep_in_memory(false),
- m_try_others(true),
- 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_one_thread_timeout_usec(0),
+ m_keep_in_memory (false),
+ m_try_others (true),
+ 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_one_thread_timeout_usec (0),
m_cancel_callback (nullptr),
m_cancel_callback_baton (nullptr)
{
@@ -247,7 +291,24 @@ public:
{
return m_coerce_to_id;
}
-
+
+ const char *
+ GetPrefix () const
+ {
+ if (m_prefix.empty())
+ return NULL;
+ return m_prefix.c_str();
+ }
+
+ void
+ SetPrefix (const char *prefix)
+ {
+ if (prefix && prefix[0])
+ m_prefix = prefix;
+ else
+ m_prefix.clear();
+ }
+
void
SetCoerceToId (bool coerce = true)
{
@@ -419,6 +480,7 @@ public:
private:
ExecutionPolicy m_execution_policy;
lldb::LanguageType m_language;
+ std::string m_prefix;
bool m_coerce_to_id;
bool m_unwind_on_error;
bool m_ignore_breakpoints;
@@ -474,35 +536,49 @@ public:
class TargetEventData : public EventData
{
public:
+ TargetEventData (const lldb::TargetSP &target_sp);
+
+ TargetEventData (const lldb::TargetSP &target_sp, const ModuleList &module_list);
+
+ virtual
+ ~TargetEventData();
static const ConstString &
GetFlavorString ();
virtual const ConstString &
- GetFlavor () const;
-
- TargetEventData (const lldb::TargetSP &new_target_sp);
-
- lldb::TargetSP &
- GetTarget()
+ GetFlavor () const
{
- return m_target_sp;
+ return TargetEventData::GetFlavorString ();
}
- virtual
- ~TargetEventData();
-
virtual void
Dump (Stream *s) const;
- static const lldb::TargetSP
- GetTargetFromEvent (const lldb::EventSP &event_sp);
-
static const TargetEventData *
- GetEventDataFromEvent (const Event *event_sp);
+ GetEventDataFromEvent (const Event *event_ptr);
+
+ static lldb::TargetSP
+ GetTargetFromEvent (const Event *event_ptr);
+
+ static ModuleList
+ GetModuleListFromEvent (const Event *event_ptr);
+
+ const lldb::TargetSP &
+ GetTarget() const
+ {
+ return m_target_sp;
+ }
+
+ const ModuleList &
+ GetModuleList() const
+ {
+ return m_module_list;
+ }
private:
lldb::TargetSP m_target_sp;
+ ModuleList m_module_list;
DISALLOW_COPY_AND_ASSIGN (TargetEventData);
};
@@ -513,14 +589,14 @@ public:
static void
SettingsTerminate ();
-// static lldb::UserSettingsControllerSP &
-// GetSettingsController ();
-
static FileSpecList
GetDefaultExecutableSearchPaths ();
static FileSpecList
GetDefaultDebugFileSearchPaths ();
+
+ static FileSpecList
+ GetDefaultClangModuleSearchPaths ();
static ArchSpec
GetDefaultArchitecture ();
@@ -539,7 +615,7 @@ public:
// Settings accessors
//----------------------------------------------------------------------
- static const TargetPropertiesSP &
+ static const lldb::TargetPropertiesSP &
GetGlobalProperties();
@@ -617,7 +693,11 @@ public:
Error
Launch (ProcessLaunchInfo &launch_info,
- Stream *stream); // Optional stream to receive first stop info
+ Stream *stream); // Optional stream to receive first stop info
+
+ Error
+ Attach (ProcessAttachInfo &attach_info,
+ Stream *stream); // Optional stream to receive first stop info
//------------------------------------------------------------------
// This part handles the breakpoints.
@@ -646,7 +726,8 @@ public:
LazyBool check_inlines,
LazyBool skip_prologue,
bool internal,
- bool request_hardware);
+ bool request_hardware,
+ LazyBool move_to_nearest_code);
// Use this to create breakpoint that matches regex against the source lines in files given in source_file_list:
lldb::BreakpointSP
@@ -654,7 +735,8 @@ public:
const FileSpecList *source_file_list,
RegularExpression &source_regex,
bool internal,
- bool request_hardware);
+ bool request_hardware,
+ LazyBool move_to_nearest_code);
// Use this to create a breakpoint from a load address
lldb::BreakpointSP
@@ -681,7 +763,8 @@ public:
// Use this to create a function breakpoint by name in containingModule, or all modules if it is NULL
// When "skip_prologue is set to eLazyBoolCalculate, we use the current target
- // setting, else we use the values passed in
+ // setting, else we use the values passed in.
+ // func_name_type_mask is or'ed values from the FunctionNameType enum.
lldb::BreakpointSP
CreateBreakpoint (const FileSpecList *containingModules,
const FileSpecList *containingSourceFiles,
@@ -692,11 +775,17 @@ public:
bool request_hardware);
lldb::BreakpointSP
- CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_bp, bool throw_bp, bool internal);
+ CreateExceptionBreakpoint (enum lldb::LanguageType language,
+ bool catch_bp,
+ bool throw_bp,
+ bool internal,
+ Args *additional_args = nullptr,
+ Error *additional_args_error = nullptr);
// This is the same as the func_name breakpoint except that you can specify a vector of names. This is cheaper
// than a regular expression breakpoint in the case where you just want to set a breakpoint on a set of names
// you already know.
+ // func_name_type_mask is or'ed values from the FunctionNameType enum.
lldb::BreakpointSP
CreateBreakpoint (const FileSpecList *containingModules,
const FileSpecList *containingSourceFiles,
@@ -779,6 +868,9 @@ public:
ClearAllWatchpointHitCounts ();
bool
+ ClearAllWatchpointHistoricValues ();
+
+ bool
IgnoreAllWatchpoints (uint32_t ignore_count);
bool
@@ -1001,12 +1093,6 @@ public:
bool
ModuleIsExcludedForUnconstrainedSearches (const lldb::ModuleSP &module_sp);
- ArchSpec &
- GetArchitecture ()
- {
- return m_arch;
- }
-
const ArchSpec &
GetArchitecture () const
{
@@ -1034,6 +1120,9 @@ public:
bool
SetArchitecture (const ArchSpec &arch_spec);
+ bool
+ MergeArchitecture (const ArchSpec &arch_spec);
+
Debugger &
GetDebugger ()
{
@@ -1182,10 +1271,7 @@ public:
const EvaluateExpressionOptions& options = EvaluateExpressionOptions());
ClangPersistentVariables &
- GetPersistentVariables()
- {
- return m_persistent_variables;
- }
+ GetPersistentVariables();
//------------------------------------------------------------------
// Target Stop Hooks
@@ -1223,10 +1309,7 @@ public:
// Set the specifier. The stop hook will own the specifier, and is responsible for deleting it when we're done.
void
- SetSpecifier (SymbolContextSpecifier *specifier)
- {
- m_specifier_sp.reset (specifier);
- }
+ SetSpecifier (SymbolContextSpecifier *specifier);
SymbolContextSpecifier *
GetSpecifier ()
@@ -1387,13 +1470,13 @@ protected:
lldb::ProcessSP m_process_sp;
lldb::SearchFilterSP m_search_filter_sp;
PathMappingList m_image_search_paths;
- std::unique_ptr<ClangASTContext> m_scratch_ast_context_ap;
- std::unique_ptr<ClangASTSource> m_scratch_ast_source_ap;
- std::unique_ptr<ClangASTImporter> m_ast_importer_ap;
- std::unique_ptr<ClangModulesDeclVendor> m_clang_modules_decl_vendor_ap;
- ClangPersistentVariables m_persistent_variables; ///< These are the persistent variables associated with this process for the expression parser.
+ lldb::ClangASTContextUP m_scratch_ast_context_ap;
+ lldb::ClangASTSourceUP m_scratch_ast_source_ap;
+ lldb::ClangASTImporterUP m_ast_importer_ap;
+ lldb::ClangModulesDeclVendorUP m_clang_modules_decl_vendor_ap;
+ lldb::ClangPersistentVariablesUP m_persistent_variables; ///< These are the persistent variables associated with this process for the expression parser.
- std::unique_ptr<SourceManager> m_source_manager_ap;
+ lldb::SourceManagerUP m_source_manager_ap;
typedef std::map<lldb::user_id_t, StopHookSP> StopHookCollection;
StopHookCollection m_stop_hooks;
diff --git a/include/lldb/Target/Thread.h b/include/lldb/Target/Thread.h
index 25c0c0e92bec..c6a3c8e9851a 100644
--- a/include/lldb/Target/Thread.h
+++ b/include/lldb/Target/Thread.h
@@ -205,22 +205,23 @@ public:
void
SetState (lldb::StateType state);
- lldb::StateType
- GetResumeState () const
- {
- 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.
+ //------------------------------------------------------------------
+ /// Sets the USER resume state for this thread. If you set a thread to suspended with
+ /// this API, it won't take part in any of the arbitration for ShouldResume, and will stay
+ /// suspended even when other threads do get to run.
+ ///
+ /// N.B. This is not the state that is used internally by thread plans to implement
+ /// staying on one thread while stepping over a breakpoint, etc. The is the
+ /// TemporaryResume state, and if you are implementing some bit of strategy in the stepping
+ /// machinery you should be using that state and not the user resume state.
+ ///
+ /// 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.
+ /// @return
+ /// The User resume state for this thread.
+ //------------------------------------------------------------------
void
SetResumeState (lldb::StateType state, bool override_suspend = false)
{
@@ -229,6 +230,21 @@ public:
m_resume_state = state;
}
+ //------------------------------------------------------------------
+ /// Gets the USER resume state for this thread. This is not the same as what
+ /// this thread is going to do for any particular step, however if this thread
+ /// returns eStateSuspended, then the process control logic will never allow this
+ /// thread to run.
+ ///
+ /// @return
+ /// The User resume state for this thread.
+ //------------------------------------------------------------------
+ lldb::StateType
+ GetResumeState () const
+ {
+ return m_resume_state;
+ }
+
// This function is called on all the threads before "ShouldResume" and
// "WillResume" in case a thread needs to change its state before the
// ThreadList polls all the threads to figure out which ones actually
@@ -1315,8 +1331,8 @@ protected:
lldb::ProcessWP m_process_wp; ///< The process that owns this thread.
lldb::StopInfoSP m_stop_info_sp; ///< The private stop reason for this thread
uint32_t m_stop_info_stop_id; // This is the stop id for which the StopInfo is valid. Can use this so you know that
- uint32_t m_stop_info_override_stop_id; // The stop ID containing the last time the stop info was checked against the stop info override
// the thread's m_stop_info_sp is current and you don't have to fetch it again
+ uint32_t m_stop_info_override_stop_id; // The stop ID containing the last time the stop info was checked against the stop info override
const uint32_t m_index_id; ///< A unique 1 based index assigned to each thread for easy UI/command line access.
lldb::RegisterContextSP m_reg_context_sp; ///< The register context for this thread's current register state.
lldb::StateType m_state; ///< The state of our process.
diff --git a/include/lldb/Target/ThreadPlanCallUserExpression.h b/include/lldb/Target/ThreadPlanCallUserExpression.h
index 67ac642de7bd..e40762c928b5 100644
--- a/include/lldb/Target/ThreadPlanCallUserExpression.h
+++ b/include/lldb/Target/ThreadPlanCallUserExpression.h
@@ -15,7 +15,6 @@
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-private.h"
-#include "lldb/Expression/ClangUserExpression.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
@@ -31,7 +30,7 @@ public:
Address &function,
llvm::ArrayRef<lldb::addr_t> args,
const EvaluateExpressionOptions &options,
- ClangUserExpression::ClangUserExpressionSP &user_expression_sp);
+ lldb::ClangUserExpressionSP &user_expression_sp);
virtual
~ThreadPlanCallUserExpression ();
@@ -62,12 +61,12 @@ public:
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.
+ lldb::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.
+ 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/ThreadPlanPython.h b/include/lldb/Target/ThreadPlanPython.h
index fa41af1915cd..ffcee018a5fb 100644
--- a/include/lldb/Target/ThreadPlanPython.h
+++ b/include/lldb/Target/ThreadPlanPython.h
@@ -16,6 +16,7 @@
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-private.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Core/UserID.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Target/Process.h"
@@ -68,8 +69,8 @@ protected:
GetPlanRunState ();
private:
- std::string m_class_name;
- lldb::ScriptInterpreterObjectSP m_implementation_sp;
+ std::string m_class_name;
+ StructuredData::ObjectSP m_implementation_sp;
DISALLOW_COPY_AND_ASSIGN(ThreadPlanPython);
};
diff --git a/include/lldb/Utility/ConvertEnum.h b/include/lldb/Utility/ConvertEnum.h
new file mode 100644
index 000000000000..6d37484b0112
--- /dev/null
+++ b/include/lldb/Utility/ConvertEnum.h
@@ -0,0 +1,22 @@
+//===-- ConvertEnum.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_UTILITY_CONVERTENUM_H
+#define LLDB_UTILITY_CONVERTENUM_H
+
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private-enumerations.h"
+
+namespace lldb_private
+{
+
+const char *GetVoteAsCString(Vote vote);
+const char *GetSectionTypeAsCString(lldb::SectionType sect_type);
+}
+
+#endif
diff --git a/include/lldb/Utility/JSON.h b/include/lldb/Utility/JSON.h
new file mode 100644
index 000000000000..45ddb71b5e03
--- /dev/null
+++ b/include/lldb/Utility/JSON.h
@@ -0,0 +1,276 @@
+//===---------------------JSON.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_JSON_h_
+#define utility_JSON_h_
+
+#include "lldb/Core/Stream.h"
+
+#include <inttypes.h>
+#include <map>
+#include <memory>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "llvm/Support/Casting.h"
+
+namespace lldb_private {
+ class JSONValue
+ {
+ public:
+ virtual void
+ Write (Stream& s) = 0;
+
+ typedef std::shared_ptr<JSONValue> SP;
+
+ enum class Kind
+ {
+ String,
+ Number,
+ True,
+ False,
+ Null,
+ Object,
+ Array
+ };
+
+ JSONValue (Kind k) :
+ m_kind(k)
+ {}
+
+ Kind
+ GetKind() const
+ {
+ return m_kind;
+ }
+
+ virtual
+ ~JSONValue () = default;
+
+ private:
+ const Kind m_kind;
+ };
+
+ class JSONString : public JSONValue
+ {
+ public:
+ JSONString ();
+ JSONString (const char* s);
+ JSONString (const std::string& s);
+
+ JSONString (const JSONString& s) = delete;
+ JSONString&
+ operator = (const JSONString& s) = delete;
+
+ virtual void
+ Write (Stream& s);
+
+ typedef std::shared_ptr<JSONString> SP;
+
+ std::string
+ GetData () { return m_data; }
+
+ static bool classof(const JSONValue *V)
+ {
+ return V->GetKind() == JSONValue::Kind::String;
+ }
+
+ virtual
+ ~JSONString () = default;
+
+ private:
+
+ static std::string
+ json_string_quote_metachars (const std::string&);
+
+ std::string m_data;
+ };
+
+ class JSONNumber : public JSONValue
+ {
+ public:
+ JSONNumber ();
+ JSONNumber (int64_t i);
+
+ JSONNumber (const JSONNumber& s) = delete;
+ JSONNumber&
+ operator = (const JSONNumber& s) = delete;
+
+ virtual void
+ Write (Stream& s);
+
+ typedef std::shared_ptr<JSONNumber> SP;
+
+ int64_t
+ GetData () { return m_data; }
+
+ static bool classof(const JSONValue *V)
+ {
+ return V->GetKind() == JSONValue::Kind::Number;
+ }
+
+ virtual
+ ~JSONNumber () = default;
+
+ private:
+ int64_t m_data;
+ };
+
+ class JSONTrue : public JSONValue
+ {
+ public:
+ JSONTrue ();
+
+ JSONTrue (const JSONTrue& s) = delete;
+ JSONTrue&
+ operator = (const JSONTrue& s) = delete;
+
+ virtual void
+ Write (Stream& s);
+
+ typedef std::shared_ptr<JSONTrue> SP;
+
+ static bool classof(const JSONValue *V)
+ {
+ return V->GetKind() == JSONValue::Kind::True;
+ }
+
+ virtual
+ ~JSONTrue () = default;
+ };
+
+ class JSONFalse : public JSONValue
+ {
+ public:
+ JSONFalse ();
+
+ JSONFalse (const JSONFalse& s) = delete;
+ JSONFalse&
+ operator = (const JSONFalse& s) = delete;
+
+ virtual void
+ Write (Stream& s);
+
+ typedef std::shared_ptr<JSONFalse> SP;
+
+ static bool classof(const JSONValue *V)
+ {
+ return V->GetKind() == JSONValue::Kind::False;
+ }
+
+ virtual
+ ~JSONFalse () = default;
+ };
+
+ class JSONNull : public JSONValue
+ {
+ public:
+ JSONNull ();
+
+ JSONNull (const JSONNull& s) = delete;
+ JSONNull&
+ operator = (const JSONNull& s) = delete;
+
+ virtual void
+ Write (Stream& s);
+
+ typedef std::shared_ptr<JSONNull> SP;
+
+ static bool classof(const JSONValue *V)
+ {
+ return V->GetKind() == JSONValue::Kind::Null;
+ }
+
+ virtual
+ ~JSONNull () = default;
+ };
+
+ class JSONObject : public JSONValue
+ {
+ public:
+ JSONObject ();
+
+ JSONObject (const JSONObject& s) = delete;
+ JSONObject&
+ operator = (const JSONObject& s) = delete;
+
+ virtual void
+ Write (Stream& s);
+
+ typedef std::shared_ptr<JSONObject> SP;
+
+ static bool classof(const JSONValue *V)
+ {
+ return V->GetKind() == JSONValue::Kind::Object;
+ }
+
+ bool
+ SetObject (const std::string& key,
+ JSONValue::SP value);
+
+ JSONValue::SP
+ GetObject (const std::string& key);
+
+ virtual
+ ~JSONObject () = default;
+
+ private:
+ typedef std::map<std::string, JSONValue::SP> Map;
+ typedef Map::iterator Iterator;
+ Map m_elements;
+ };
+
+ class JSONArray : public JSONValue
+ {
+ public:
+ JSONArray ();
+
+ JSONArray (const JSONArray& s) = delete;
+ JSONArray&
+ operator = (const JSONArray& s) = delete;
+
+ virtual void
+ Write (Stream& s);
+
+ typedef std::shared_ptr<JSONArray> SP;
+
+ static bool classof(const JSONValue *V)
+ {
+ return V->GetKind() == JSONValue::Kind::Array;
+ }
+
+ private:
+ typedef std::vector<JSONValue::SP> Vector;
+ typedef Vector::iterator Iterator;
+ typedef Vector::size_type Index;
+ typedef Vector::size_type Size;
+
+ public:
+ bool
+ SetObject (Index i,
+ JSONValue::SP value);
+
+ bool
+ AppendObject (JSONValue::SP value);
+
+ JSONValue::SP
+ GetObject (Index i);
+
+ Size
+ GetNumElements ();
+
+ virtual
+ ~JSONArray () = default;
+
+ Vector m_elements;
+ };
+}
+
+#endif // utility_ProcessStructReader_h_
diff --git a/include/lldb/Utility/LLDBAssert.h b/include/lldb/Utility/LLDBAssert.h
new file mode 100644
index 000000000000..5ca252f20032
--- /dev/null
+++ b/include/lldb/Utility/LLDBAssert.h
@@ -0,0 +1,30 @@
+//===----------------- LLDBAssert.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_LLDBAssert_h_
+#define utility_LLDBAssert_h_
+
+#include <assert.h>
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+#define lldbassert(x) assert(x)
+#else
+#define lldbassert(x) lldb_private::lldb_assert(x, #x, __FUNCTION__, __FILE__, __LINE__)
+#endif
+
+namespace lldb_private {
+ void
+ lldb_assert (bool expression,
+ const char* expr_text,
+ const char* func,
+ const char* file,
+ unsigned int line);
+}
+
+#endif // utility_LLDBAssert_h_
diff --git a/include/lldb/Utility/NameMatches.h b/include/lldb/Utility/NameMatches.h
new file mode 100644
index 000000000000..5fe6565d06f9
--- /dev/null
+++ b/include/lldb/Utility/NameMatches.h
@@ -0,0 +1,19 @@
+//===-- NameMatches.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_UTILITY_NAMEMATCHES_H
+#define LLDB_UTILITY_NAMEMATCHES_H
+
+#include "lldb/lldb-private-enumerations.h"
+
+namespace lldb_private
+{
+bool NameMatches(const char *name, NameMatchType match_type, const char *match);
+}
+
+#endif
diff --git a/include/lldb/Utility/PseudoTerminal.h b/include/lldb/Utility/PseudoTerminal.h
index 6ee598cefe08..595b2fc19bfd 100644
--- a/include/lldb/Utility/PseudoTerminal.h
+++ b/include/lldb/Utility/PseudoTerminal.h
@@ -175,7 +175,7 @@ public:
/// occur. This can be NULL if no error status is desired.
///
/// @return
- /// @li \b true when the a master files descriptor is
+ /// @li \b true when the master files descriptor is
/// successfully opened.
/// @li \b false if anything goes wrong.
///
@@ -207,7 +207,7 @@ public:
/// occur. This can be NULL if no error status is desired.
///
/// @return
- /// @li \b true when the a master files descriptor is
+ /// @li \b true when the master files descriptor is
/// successfully opened.
/// @li \b false if anything goes wrong.
///
diff --git a/include/lldb/Utility/SharingPtr.h b/include/lldb/Utility/SharingPtr.h
index 1b5f86bbe2df..5c77dad9f7ff 100644
--- a/include/lldb/Utility/SharingPtr.h
+++ b/include/lldb/Utility/SharingPtr.h
@@ -154,6 +154,7 @@ public:
void swap(SharingPtr& r);
void reset();
template<class Y> void reset(Y* p);
+ void reset(std::nullptr_t);
element_type* get() const {return ptr_;}
element_type& operator*() const {return *ptr_;}
@@ -295,6 +296,14 @@ SharingPtr<T>::reset()
}
template<class T>
+inline
+void
+SharingPtr<T>::reset (std::nullptr_t p)
+{
+ reset();
+}
+
+template<class T>
template<class Y>
inline
void
@@ -547,7 +556,7 @@ public:
if (cb_)
cb_(baton_, *this, false);
}
-
+
void SetCallback(Callback cb, void* baton)
{
cb_ = cb;
diff --git a/include/lldb/lldb-defines.h b/include/lldb/lldb-defines.h
index add182c13ecb..9dce69aef32b 100644
--- a/include/lldb/lldb-defines.h
+++ b/include/lldb/lldb-defines.h
@@ -12,7 +12,7 @@
#include "lldb/lldb-types.h"
-#if defined (_WIN32)
+#if defined (_MSC_VER)
#if defined(EXPORT_LIBLLDB)
#define LLDB_API __declspec(dllexport)
#elif defined(IMPORT_LIBLLDB)
diff --git a/include/lldb/lldb-enumerations.h b/include/lldb/lldb-enumerations.h
index f70ee0cd7b28..28614ffb23e1 100644
--- a/include/lldb/lldb-enumerations.h
+++ b/include/lldb/lldb-enumerations.h
@@ -10,12 +10,34 @@
#ifndef LLDB_lldb_enumerations_h_
#define LLDB_lldb_enumerations_h_
+#ifndef SWIG
+// With MSVC, the default type of an enum is always signed, even if one of the
+// enumerator values is too large to fit into a signed integer but would
+// otherwise fit into an unsigned integer. As a result of this, all of LLDB's
+// flag-style enumerations that specify something like eValueFoo = 1u << 31
+// result in negative values. This usually just results in a benign warning,
+// but in a few places we actually do comparisons on the enum values, which
+// would cause a real bug. Furthermore, there's no way to silence only this
+// warning, as it's part of -Wmicrosoft which also catches a whole slew of
+// other useful issues.
+//
+// To make matters worse, early versions of SWIG don't recognize the syntax
+// of specifying the underlying type of an enum (and Python doesn't care anyway)
+// so we need a way to specify the underlying type when the enum is being used
+// from C++ code, but just use a regular enum when swig is pre-processing.
+#define FLAGS_ENUM(Name) enum Name : unsigned
+#define FLAGS_ANONYMOUS_ENUM() enum : unsigned
+#else
+#define FLAGS_ENUM(Name) enum Name
+#define FLAGS_ANONYMOUS_ENUM() enum
+#endif
+
namespace lldb {
//----------------------------------------------------------------------
// Process and Thread States
//----------------------------------------------------------------------
- typedef enum StateType
+ enum StateType
{
eStateInvalid = 0,
eStateUnloaded, ///< Process is object is valid, but not currently loaded
@@ -31,12 +53,12 @@ namespace lldb {
eStateSuspended ///< Process or thread is in a suspended state as far
///< as the debugger is concerned while other processes
///< or threads get the chance to run.
- } StateType;
+ };
//----------------------------------------------------------------------
// Launch Flags
//----------------------------------------------------------------------
- typedef enum LaunchFlags
+ FLAGS_ENUM(LaunchFlags)
{
eLaunchFlagNone = 0u,
eLaunchFlagExec = (1u << 0), ///< Exec when launching and turn the calling process into a new process
@@ -49,46 +71,49 @@ namespace lldb {
eLaunchFlagLaunchInSeparateProcessGroup = (1u << 7), ///< Launch the process in a separate process group
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
+ eLaunchFlagDetachOnError = (1u << 9), ///< If set, then the client stub should detach rather than killing the debugee
///< if it loses connection with lldb.
- } LaunchFlags;
+ eLaunchFlagShellExpandArguments = (1u << 10), ///< Perform shell-style argument expansion
+ eLaunchFlagCloseTTYOnExit = (1u << 11), ///< Close the open TTY on exit
+ };
//----------------------------------------------------------------------
// Thread Run Modes
//----------------------------------------------------------------------
- typedef enum RunMode {
+ enum RunMode
+ {
eOnlyThisThread,
eAllThreads,
eOnlyDuringStepping
- } RunMode;
+ };
//----------------------------------------------------------------------
// Byte ordering definitions
//----------------------------------------------------------------------
- typedef enum ByteOrder
+ enum ByteOrder
{
eByteOrderInvalid = 0,
eByteOrderBig = 1,
eByteOrderPDP = 2,
eByteOrderLittle = 4
- } ByteOrder;
+ };
//----------------------------------------------------------------------
// Register encoding definitions
//----------------------------------------------------------------------
- typedef enum Encoding
+ enum Encoding
{
eEncodingInvalid = 0,
eEncodingUint, // unsigned integer
eEncodingSint, // signed integer
eEncodingIEEE754, // float
eEncodingVector // vector registers
- } Encoding;
+ };
//----------------------------------------------------------------------
// Display format definitions
//----------------------------------------------------------------------
- typedef enum Format
+ enum Format
{
eFormatDefault = 0,
eFormatInvalid = 0,
@@ -131,29 +156,29 @@ namespace lldb {
eFormatInstruction, // Disassemble an opcode
eFormatVoid, // Do not print this
kNumFormats
- } Format;
+ };
//----------------------------------------------------------------------
// Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls
//----------------------------------------------------------------------
- typedef enum DescriptionLevel
+ enum DescriptionLevel
{
eDescriptionLevelBrief = 0,
eDescriptionLevelFull,
eDescriptionLevelVerbose,
eDescriptionLevelInitial,
kNumDescriptionLevels
- } DescriptionLevel;
+ };
//----------------------------------------------------------------------
// Script interpreter types
//----------------------------------------------------------------------
- typedef enum ScriptLanguage
+ enum ScriptLanguage
{
eScriptLanguageNone,
eScriptLanguagePython,
eScriptLanguageDefault = eScriptLanguagePython
- } ScriptLanguage;
+ };
//----------------------------------------------------------------------
// Register numbering types
@@ -161,7 +186,7 @@ namespace lldb {
// any of these to the lldb internal register numbering scheme
// (eRegisterKindLLDB).
//----------------------------------------------------------------------
- typedef enum RegisterKind
+ enum RegisterKind
{
eRegisterKindGCC = 0, // the register numbers seen in eh_frame
eRegisterKindDWARF, // the register numbers seen DWARF
@@ -169,12 +194,12 @@ namespace lldb {
eRegisterKindGDB, // the register numbers gdb uses (matches stabs numbers)
eRegisterKindLLDB, // lldb's internal register numbers
kNumRegisterKinds
- } RegisterKind;
+ };
//----------------------------------------------------------------------
// Thread stop reasons
//----------------------------------------------------------------------
- typedef enum StopReason
+ enum StopReason
{
eStopReasonInvalid = 0,
eStopReasonNone,
@@ -187,12 +212,12 @@ namespace lldb {
eStopReasonPlanComplete,
eStopReasonThreadExiting,
eStopReasonInstrumentation
- } StopReason;
+ };
//----------------------------------------------------------------------
// Command Return Status Types
//----------------------------------------------------------------------
- typedef enum ReturnStatus
+ enum ReturnStatus
{
eReturnStatusInvalid,
eReturnStatusSuccessFinishNoResult,
@@ -202,13 +227,13 @@ namespace lldb {
eReturnStatusStarted,
eReturnStatusFailed,
eReturnStatusQuit
- } ReturnStatus;
+ };
//----------------------------------------------------------------------
// The results of expression evaluation:
//----------------------------------------------------------------------
- typedef enum ExpressionResults
+ enum ExpressionResults
{
eExpressionCompleted = 0,
eExpressionSetupError,
@@ -219,12 +244,12 @@ namespace lldb {
eExpressionTimedOut,
eExpressionResultUnavailable,
eExpressionStoppedForDebug
- } ExpressionResults;
+ };
//----------------------------------------------------------------------
// Connection Status Types
//----------------------------------------------------------------------
- typedef enum ConnectionStatus
+ enum ConnectionStatus
{
eConnectionStatusSuccess, // Success
eConnectionStatusEndOfFile, // End-of-file encountered
@@ -233,9 +258,9 @@ namespace lldb {
eConnectionStatusNoConnection, // No connection
eConnectionStatusLostConnection, // Lost connection while connected to a valid connection
eConnectionStatusInterrupted // Interrupted read
- } ConnectionStatus;
+ };
- typedef enum ErrorType
+ enum ErrorType
{
eErrorTypeInvalid,
eErrorTypeGeneric, ///< Generic errors that can be any value.
@@ -243,10 +268,10 @@ namespace lldb {
eErrorTypePOSIX, ///< POSIX error codes.
eErrorTypeExpression, ///< These are from the ExpressionResults enum.
eErrorTypeWin32 ///< Standard Win32 error codes.
- } ErrorType;
+ };
- typedef enum ValueType
+ enum ValueType
{
eValueTypeInvalid = 0,
eValueTypeVariableGlobal = 1, // globals variable
@@ -256,20 +281,20 @@ namespace lldb {
eValueTypeRegister = 5, // stack frame register value
eValueTypeRegisterSet = 6, // A collection of stack frame register values
eValueTypeConstResult = 7 // constant result variables
- } ValueType;
+ };
//----------------------------------------------------------------------
// Token size/granularities for Input Readers
//----------------------------------------------------------------------
- typedef enum InputReaderGranularity
+ enum InputReaderGranularity
{
eInputReaderGranularityInvalid = 0,
eInputReaderGranularityByte,
eInputReaderGranularityWord,
eInputReaderGranularityLine,
eInputReaderGranularityAll
- } InputReaderGranularity;
+ };
//------------------------------------------------------------------
/// These mask bits allow a common interface for queries that can
@@ -281,7 +306,7 @@ namespace lldb {
/// in this class, and requests that that item be resolved, or
/// indicates that the member did get resolved.
//------------------------------------------------------------------
- typedef enum SymbolContextItem
+ FLAGS_ENUM(SymbolContextItem)
{
eSymbolContextTarget = (1u << 0), ///< Set when \a target is requested from a query, or was located in query results
eSymbolContextModule = (1u << 1), ///< Set when \a module is requested from a query, or was located in query results
@@ -295,16 +320,16 @@ namespace lldb {
///< eSymbolContextVariable is potentially expensive to lookup so it isn't included in
///< eSymbolContextEverything which stops it from being used during frame PC lookups and
///< many other potential address to symbol context lookups.
- } SymbolContextItem;
+ };
- typedef enum Permissions
+ FLAGS_ENUM(Permissions)
{
ePermissionsWritable = (1u << 0),
ePermissionsReadable = (1u << 1),
ePermissionsExecutable = (1u << 2)
- } Permissions;
+ };
- typedef enum InputReaderAction
+ enum InputReaderAction
{
eInputReaderActivate, // reader is newly pushed onto the reader stack
eInputReaderAsynchronousOutputWritten, // an async output event occurred; the reader may want to do something
@@ -314,9 +339,9 @@ namespace lldb {
eInputReaderInterrupt, // reader received an interrupt signal (probably from a control-c)
eInputReaderEndOfFile, // reader received an EOF char (probably from a control-d)
eInputReaderDone // reader was just popped off the stack and is done
- } InputReaderAction;
+ };
- typedef enum BreakpointEventType
+ FLAGS_ENUM(BreakpointEventType)
{
eBreakpointEventTypeInvalidType = (1u << 0),
eBreakpointEventTypeAdded = (1u << 1),
@@ -330,9 +355,9 @@ namespace lldb {
eBreakpointEventTypeConditionChanged = (1u << 9),
eBreakpointEventTypeIgnoreChanged = (1u << 10),
eBreakpointEventTypeThreadChanged = (1u << 11)
- } BreakpointEventType;
+ };
- typedef enum WatchpointEventType
+ FLAGS_ENUM(WatchpointEventType)
{
eWatchpointEventTypeInvalidType = (1u << 0),
eWatchpointEventTypeAdded = (1u << 1),
@@ -344,7 +369,7 @@ namespace lldb {
eWatchpointEventTypeIgnoreChanged = (1u << 10),
eWatchpointEventTypeThreadChanged = (1u << 11),
eWatchpointEventTypeTypeChanged = (1u << 12)
- } WatchpointEventType;
+ };
//----------------------------------------------------------------------
@@ -355,7 +380,7 @@ namespace lldb {
/// The enum -> string code is in LanguageRuntime.cpp, don't change this
/// table without updating that code as well.
//----------------------------------------------------------------------
- typedef enum LanguageType
+ enum LanguageType
{
eLanguageTypeUnknown = 0x0000, ///< Unknown or invalid language value.
eLanguageTypeC89 = 0x0001, ///< ISO C:1989.
@@ -395,31 +420,39 @@ namespace lldb {
eLanguageTypeC_plus_plus_14 = 0x0021, ///< ISO C++:2014.
eLanguageTypeFortran03 = 0x0022, ///< ISO Fortran 2003.
eLanguageTypeFortran08 = 0x0023, ///< ISO Fortran 2008.
+ // Vendor Extensions
+ // Note: LanguageRuntime::GetNameForLanguageType
+ // assumes these can be used as indexes into array language_names, and
+ // Language::SetLanguageFromCString and Language::AsCString
+ // assume these can be used as indexes into array g_languages.
+ eLanguageTypeMipsAssembler = 0x0024, ///< Mips_Assembler.
+ eLanguageTypeExtRenderScript = 0x0025, ///< RenderScript.
eNumLanguageTypes
- } LanguageType;
+ };
- typedef enum InstrumentationRuntimeType {
+ enum InstrumentationRuntimeType
+ {
eInstrumentationRuntimeTypeAddressSanitizer = 0x0000,
eNumInstrumentationRuntimeTypes
- } InstrumentationRuntimeType;
+ };
- typedef enum DynamicValueType
+ enum DynamicValueType
{
eNoDynamicValues = 0,
eDynamicCanRunTarget = 1,
eDynamicDontRunTarget = 2
- } DynamicValueType;
+ };
- typedef enum AccessType
+ enum AccessType
{
eAccessNone,
eAccessPublic,
eAccessPrivate,
eAccessProtected,
eAccessPackage
- } AccessType;
+ };
- typedef enum CommandArgumentType
+ enum CommandArgumentType
{
eArgTypeAddress = 0,
eArgTypeAddressOrExpression,
@@ -493,6 +526,7 @@ namespace lldb {
eArgTypeThreadID,
eArgTypeThreadIndex,
eArgTypeThreadName,
+ eArgTypeTypeName,
eArgTypeUnsignedInteger,
eArgTypeUnixSignal,
eArgTypeVarName,
@@ -504,12 +538,12 @@ namespace lldb {
eArgTypeWatchpointIDRange,
eArgTypeWatchType,
eArgTypeLastArg // Always keep this entry as the last entry in this enumeration!!
- } CommandArgumentType;
+ };
//----------------------------------------------------------------------
// Symbol types
//----------------------------------------------------------------------
- typedef enum SymbolType
+ enum SymbolType
{
eSymbolTypeAny = 0,
eSymbolTypeInvalid = 0,
@@ -541,9 +575,9 @@ namespace lldb {
eSymbolTypeObjCMetaClass,
eSymbolTypeObjCIVar,
eSymbolTypeReExported
- } SymbolType;
+ };
- typedef enum SectionType
+ enum SectionType
{
eSectionTypeInvalid,
eSectionTypeCode,
@@ -582,17 +616,16 @@ namespace lldb {
eSectionTypeEHFrame,
eSectionTypeCompactUnwind, // compact unwind section in Mach-O, __TEXT,__unwind_info
eSectionTypeOther
-
- } SectionType;
+ };
- typedef enum EmulateInstructionOptions
+ FLAGS_ENUM(EmulateInstructionOptions)
{
eEmulateInstructionOptionNone = (0u),
eEmulateInstructionOptionAutoAdvancePC = (1u << 0),
eEmulateInstructionOptionIgnoreConditions = (1u << 1)
- } EmulateInstructionOptions;
+ };
- typedef enum FunctionNameType
+ FLAGS_ENUM(FunctionNameType)
{
eFunctionNameTypeNone = 0u,
eFunctionNameTypeAuto = (1u << 1), // Automatically figure out which FunctionNameType
@@ -607,13 +640,13 @@ namespace lldb {
eFunctionNameTypeMethod = (1u << 4), // Find function by method name (C++) with no namespace or arguments
eFunctionNameTypeSelector = (1u << 5), // Find function by selector name (ObjC) names
eFunctionNameTypeAny = eFunctionNameTypeAuto // DEPRECATED: use eFunctionNameTypeAuto
- } FunctionNameType;
+ };
//----------------------------------------------------------------------
// Basic types enumeration for the public API SBType::GetBasicType()
//----------------------------------------------------------------------
- typedef enum BasicType
+ enum BasicType
{
eBasicTypeInvalid = 0,
eBasicTypeVoid = 1,
@@ -648,9 +681,9 @@ namespace lldb {
eBasicTypeObjCSel,
eBasicTypeNullPtr,
eBasicTypeOther
- } BasicType;
+ };
- typedef enum TypeClass
+ FLAGS_ENUM(TypeClass)
{
eTypeClassInvalid = (0u),
eTypeClassArray = (1u << 0),
@@ -675,9 +708,9 @@ namespace lldb {
eTypeClassOther = (1u << 31),
// Define a mask that can be used for any type when finding types
eTypeClassAny = (0xffffffffu)
- } TypeClass;
+ };
- typedef enum TemplateArgumentKind
+ enum TemplateArgumentKind
{
eTemplateArgumentKindNull = 0,
eTemplateArgumentKindType,
@@ -688,13 +721,13 @@ namespace lldb {
eTemplateArgumentKindExpression,
eTemplateArgumentKindPack
- } TemplateArgumentKind;
+ };
//----------------------------------------------------------------------
// Options that can be set for a formatter to alter its behavior
// Not all of these are applicable to all formatter types
//----------------------------------------------------------------------
- typedef enum TypeOptions
+ FLAGS_ENUM(TypeOptions)
{
eTypeOptionNone = (0u),
eTypeOptionCascade = (1u << 0),
@@ -703,8 +736,9 @@ namespace lldb {
eTypeOptionHideChildren = (1u << 3),
eTypeOptionHideValue = (1u << 4),
eTypeOptionShowOneLiner = (1u << 5),
- eTypeOptionHideNames = (1u << 6)
- } TypeOptions;
+ eTypeOptionHideNames = (1u << 6),
+ eTypeOptionNonCacheable = (1u << 7)
+ };
//----------------------------------------------------------------------
// This is the return value for frame comparisons. If you are comparing frame A to frame B
@@ -717,7 +751,7 @@ namespace lldb {
// 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
+ enum FrameComparison
{
eFrameCompareInvalid,
eFrameCompareUnknown,
@@ -725,7 +759,7 @@ namespace lldb {
eFrameCompareSameParent,
eFrameCompareYounger,
eFrameCompareOlder
- } FrameComparison;
+ };
//----------------------------------------------------------------------
// Address Class
@@ -737,7 +771,7 @@ namespace lldb {
// might contain PC relative data and the object file might be able to
// tell us that an address in code is data.
//----------------------------------------------------------------------
- typedef enum AddressClass
+ enum AddressClass
{
eAddressClassInvalid,
eAddressClassUnknown,
@@ -746,7 +780,7 @@ namespace lldb {
eAddressClassData,
eAddressClassDebug,
eAddressClassRuntime
- } AddressClass;
+ };
//----------------------------------------------------------------------
// File Permissions
@@ -755,7 +789,7 @@ namespace lldb {
// used with functions that set 'mode_t' to certain values for
// permissions.
//----------------------------------------------------------------------
- typedef enum FilePermissions
+ FLAGS_ENUM(FilePermissions)
{
eFilePermissionsUserRead = (1u << 8),
eFilePermissionsUserWrite = (1u << 7),
@@ -788,7 +822,7 @@ namespace lldb {
eFilePermissionsEveryoneRWX = (eFilePermissionsEveryoneR | eFilePermissionsEveryoneW | eFilePermissionsEveryoneX ),
eFilePermissionsFileDefault = eFilePermissionsUserRW,
eFilePermissionsDirectoryDefault = eFilePermissionsUserRWX,
- } FilePermissions;
+ };
//----------------------------------------------------------------------
// Queue work item types
@@ -796,24 +830,24 @@ namespace lldb {
// The different types of work that can be enqueued on a libdispatch
// aka Grand Central Dispatch (GCD) queue.
//----------------------------------------------------------------------
- typedef enum QueueItemKind
+ enum QueueItemKind
{
eQueueItemKindUnknown = 0,
eQueueItemKindFunction,
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
+ enum QueueKind
{
eQueueKindUnknown = 0,
eQueueKindSerial,
eQueueKindConcurrent
- } QueueKind;
+ };
//----------------------------------------------------------------------
// Expression Evaluation Stages
@@ -821,13 +855,13 @@ namespace lldb {
// expression evaluation callback, so that you can interrupt expression
// evaluation at the various points in its lifecycle.
//----------------------------------------------------------------------
- typedef enum ExpressionEvaluationPhase
+ enum ExpressionEvaluationPhase
{
eExpressionEvaluationParse = 0,
eExpressionEvaluationIRGen,
eExpressionEvaluationExecution,
eExpressionEvaluationComplete
- } ExpressionEvaluationPhase;
+ };
//----------------------------------------------------------------------
@@ -835,13 +869,13 @@ namespace lldb {
// Indicates what types of events cause the watchpoint to fire.
// Used by Native*Protocol-related classes.
//----------------------------------------------------------------------
- typedef enum WatchpointKind
+ FLAGS_ENUM(WatchpointKind)
{
eWatchpointKindRead = (1u << 0),
eWatchpointKindWrite = (1u << 1)
- } WatchpointKind;
+ };
- typedef enum GdbSignal
+ enum GdbSignal
{
eGdbSignalBadAccess = 0x91,
eGdbSignalBadInstruction = 0x92,
@@ -849,52 +883,55 @@ namespace lldb {
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
- ePathTypeClangDir // Find path to Clang builtin headers
- } PathType;
+ 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
+ ePathTypeGlobalLLDBTempSystemDir, // The LLDB temp directory for this system, NOT cleaned up on a process exit.
+ ePathTypeClangDir // Find path to Clang builtin headers
+ };
//----------------------------------------------------------------------
// Kind of member function
// Used by the type system
//----------------------------------------------------------------------
- typedef enum MemberFunctionKind
+ enum MemberFunctionKind
{
eMemberFunctionKindUnknown = 0, // Not sure what the type of this is
eMemberFunctionKindConstructor, // A function used to create instances
eMemberFunctionKindDestructor, // A function used to tear down existing instances
eMemberFunctionKindInstanceMethod, // A function that applies to a specific instance
eMemberFunctionKindStaticMethod // A function that applies to a type rather than any instance
- } MemberFunctionKind;
+ };
//----------------------------------------------------------------------
// String matching algorithm used by SBTarget
//----------------------------------------------------------------------
- typedef enum MatchType {
+ enum MatchType
+ {
eMatchTypeNormal,
eMatchTypeRegex,
eMatchTypeStartsWith
- } MatchType;
+ };
//----------------------------------------------------------------------
// Bitmask that describes details about a type
//----------------------------------------------------------------------
- typedef enum TypeFlags {
+ FLAGS_ENUM(TypeFlags)
+ {
eTypeHasChildren = (1u << 0),
eTypeHasValue = (1u << 1),
eTypeIsArray = (1u << 2),
@@ -917,17 +954,100 @@ namespace lldb {
eTypeIsFloat = (1u << 19),
eTypeIsComplex = (1u << 20),
eTypeIsSigned = (1u << 21)
- } TypeFlags;
+ };
+
+ FLAGS_ENUM(CommandFlags)
+ {
+ //----------------------------------------------------------------------
+ // eCommandRequiresTarget
+ //
+ // Ensures a valid target is contained in m_exe_ctx prior to executing
+ // the command. If a target doesn't exist or is invalid, the command
+ // will fail and CommandObject::GetInvalidTargetDescription() will be
+ // returned as the error. CommandObject subclasses can override the
+ // virtual function for GetInvalidTargetDescription() to provide custom
+ // strings when needed.
+ //----------------------------------------------------------------------
+ eCommandRequiresTarget = (1u << 0),
+ //----------------------------------------------------------------------
+ // eCommandRequiresProcess
+ //
+ // Ensures a valid process is contained in m_exe_ctx prior to executing
+ // the command. If a process doesn't exist or is invalid, the command
+ // will fail and CommandObject::GetInvalidProcessDescription() will be
+ // returned as the error. CommandObject subclasses can override the
+ // virtual function for GetInvalidProcessDescription() to provide custom
+ // strings when needed.
+ //----------------------------------------------------------------------
+ eCommandRequiresProcess = (1u << 1),
+ //----------------------------------------------------------------------
+ // eCommandRequiresThread
+ //
+ // Ensures a valid thread is contained in m_exe_ctx prior to executing
+ // the command. If a thread doesn't exist or is invalid, the command
+ // will fail and CommandObject::GetInvalidThreadDescription() will be
+ // returned as the error. CommandObject subclasses can override the
+ // virtual function for GetInvalidThreadDescription() to provide custom
+ // strings when needed.
+ //----------------------------------------------------------------------
+ eCommandRequiresThread = (1u << 2),
+ //----------------------------------------------------------------------
+ // eCommandRequiresFrame
+ //
+ // Ensures a valid frame is contained in m_exe_ctx prior to executing
+ // the command. If a frame doesn't exist or is invalid, the command
+ // will fail and CommandObject::GetInvalidFrameDescription() will be
+ // returned as the error. CommandObject subclasses can override the
+ // virtual function for GetInvalidFrameDescription() to provide custom
+ // strings when needed.
+ //----------------------------------------------------------------------
+ eCommandRequiresFrame = (1u << 3),
+ //----------------------------------------------------------------------
+ // eCommandRequiresRegContext
+ //
+ // 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 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
+ // for GetInvalidRegContextDescription() to provide custom strings when
+ // needed.
+ //----------------------------------------------------------------------
+ eCommandRequiresRegContext = (1u << 4),
+ //----------------------------------------------------------------------
+ // eCommandTryTargetAPILock
+ //
+ // Attempts to acquire the target lock if a target is selected in the
+ // command interpreter. If the command object fails to acquire the API
+ // lock, the command will fail with an appropriate error message.
+ //----------------------------------------------------------------------
+ eCommandTryTargetAPILock = (1u << 5),
+ //----------------------------------------------------------------------
+ // eCommandProcessMustBeLaunched
+ //
+ // Verifies that there is a launched process in m_exe_ctx, if there
+ // isn't, the command will fail with an appropriate error message.
+ //----------------------------------------------------------------------
+ eCommandProcessMustBeLaunched = (1u << 6),
+ //----------------------------------------------------------------------
+ // eCommandProcessMustBePaused
+ //
+ // Verifies that there is a paused process in m_exe_ctx, if there
+ // isn't, the command will fail with an appropriate error message.
+ //----------------------------------------------------------------------
+ eCommandProcessMustBePaused = (1u << 7)
+ };
//----------------------------------------------------------------------
// Whether a summary should cap how much data it returns to users or not
//----------------------------------------------------------------------
- typedef enum TypeSummaryCapping {
+ enum TypeSummaryCapping
+ {
eTypeSummaryCapped = true,
eTypeSummaryUncapped = false
- } TypeSummaryCapping;
+ };
} // namespace lldb
-
#endif // LLDB_lldb_enumerations_h_
diff --git a/include/lldb/lldb-forward.h b/include/lldb/lldb-forward.h
index 53f59dd62096..e0c2ae4b8b8d 100644
--- a/include/lldb/lldb-forward.h
+++ b/include/lldb/lldb-forward.h
@@ -58,6 +58,7 @@ class ClangExpressionVariableList;
class ClangExpressionVariableList;
class ClangExpressionVariables;
class ClangFunction;
+class ClangModulesDeclVendor;
class ClangPersistentVariables;
class ClangUserExpression;
class ClangUtilityFunction;
@@ -82,6 +83,7 @@ class Debugger;
class Declaration;
class Disassembler;
struct DumpValueObjectOptions;
+class DynamicCheckerFunctions;
class DynamicLoader;
class Editline;
class EmulateInstruction;
@@ -111,8 +113,9 @@ class IOHandler;
class IOObject;
class IRExecutionUnit;
class JITLoader;
+class JITLoaderList;
class LanguageRuntime;
-class SystemRuntime;
+class MemoryRegionInfo;
class LineTable;
class Listener;
class Log;
@@ -146,6 +149,7 @@ class OptionValueEnumeration;
class OptionValueFileSpec;
class OptionValueFileSpecList;
class OptionValueFormat;
+class OptionValueLanguage;
class OptionValueFormatEntity;
class OptionValuePathMappings;
class OptionValueProperties;
@@ -167,11 +171,6 @@ class ProcessInstanceInfoMatch;
class ProcessLaunchInfo;
class Property;
struct PropertyDefinition;
-class PythonArray;
-class PythonDictionary;
-class PythonInteger;
-class PythonObject;
-class PythonString;
class RegisterCheckpoint;
class RegisterContext;
class RegisterLocation;
@@ -181,9 +180,7 @@ class RegularExpression;
class Scalar;
class ScriptInterpreter;
class ScriptInterpreterLocker;
-class ScriptInterpreterObject;
#ifndef LLDB_DISABLE_PYTHON
-class ScriptInterpreterPython;
struct ScriptSummaryFormat;
#endif
class SearchFilter;
@@ -209,6 +206,7 @@ class StreamFile;
class StreamString;
class StringList;
struct StringSummaryFormat;
+class SystemRuntime;
class TypeSummaryImpl;
class TypeSummaryOptions;
class Symbol;
@@ -231,6 +229,7 @@ class QueueItem;
class QueueImpl;
class Target;
class TargetList;
+class TargetProperties;
class Thread;
class ThreadCollection;
class ThreadList;
@@ -300,7 +299,13 @@ namespace lldb {
typedef std::weak_ptr<lldb_private::BreakpointLocation> BreakpointLocationWP;
typedef std::shared_ptr<lldb_private::BreakpointResolver> BreakpointResolverSP;
typedef std::shared_ptr<lldb_private::Broadcaster> BroadcasterSP;
+ typedef std::unique_ptr<lldb_private::ClangASTContext> ClangASTContextUP;
+ typedef std::unique_ptr<lldb_private::ClangASTImporter> ClangASTImporterUP;
+ typedef std::unique_ptr<lldb_private::ClangASTSource> ClangASTSourceUP;
typedef std::shared_ptr<lldb_private::ClangExpressionVariable> ClangExpressionVariableSP;
+ typedef std::unique_ptr<lldb_private::ClangModulesDeclVendor> ClangModulesDeclVendorUP;
+ typedef std::unique_ptr<lldb_private::ClangPersistentVariables> ClangPersistentVariablesUP;
+ typedef std::shared_ptr<lldb_private::ClangUserExpression> ClangUserExpressionSP;
typedef std::shared_ptr<lldb_private::CommandObject> CommandObjectSP;
typedef std::shared_ptr<lldb_private::Communication> CommunicationSP;
typedef std::shared_ptr<lldb_private::Connection> ConnectionSP;
@@ -310,7 +315,9 @@ 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::unique_ptr<lldb_private::DynamicCheckerFunctions> DynamicCheckerFunctionsUP;
typedef std::shared_ptr<lldb_private::DynamicLoader> DynamicLoaderSP;
+ typedef std::unique_ptr<lldb_private::DynamicLoader> DynamicLoaderUP;
typedef std::shared_ptr<lldb_private::Event> EventSP;
typedef std::shared_ptr<lldb_private::ExecutionContextRef> ExecutionContextRefSP;
typedef std::shared_ptr<lldb_private::File> FileSP;
@@ -322,8 +329,10 @@ namespace lldb {
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::unique_ptr<lldb_private::JITLoaderList> JITLoaderListUP;
typedef std::shared_ptr<lldb_private::LanguageRuntime> LanguageRuntimeSP;
typedef std::shared_ptr<lldb_private::SystemRuntime> SystemRuntimeSP;
+ typedef std::unique_ptr<lldb_private::SystemRuntime> SystemRuntimeUP;
typedef std::shared_ptr<lldb_private::LineTable> LineTableSP;
typedef std::shared_ptr<lldb_private::Listener> ListenerSP;
typedef std::shared_ptr<lldb_private::LogChannel> LogChannelSP;
@@ -334,6 +343,7 @@ namespace lldb {
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::unique_ptr<lldb_private::OperatingSystem> OperatingSystemUP;
typedef std::shared_ptr<lldb_private::OptionValue> OptionValueSP;
typedef std::weak_ptr<lldb_private::OptionValue> OptionValueWP;
typedef std::shared_ptr<lldb_private::OptionValueArch> OptionValueArchSP;
@@ -363,15 +373,16 @@ namespace lldb {
typedef std::shared_ptr<lldb_private::Queue> QueueSP;
typedef std::weak_ptr<lldb_private::Queue> QueueWP;
typedef std::shared_ptr<lldb_private::QueueItem> QueueItemSP;
- typedef std::shared_ptr<lldb_private::ScriptInterpreterObject> ScriptInterpreterObjectSP;
#ifndef LLDB_DISABLE_PYTHON
typedef std::shared_ptr<lldb_private::ScriptSummaryFormat> ScriptSummaryFormatSP;
#endif // #ifndef LLDB_DISABLE_PYTHON
typedef std::shared_ptr<lldb_private::Section> SectionSP;
+ typedef std::unique_ptr<lldb_private::SectionList> SectionListUP;
typedef std::weak_ptr<lldb_private::Section> SectionWP;
typedef std::shared_ptr<lldb_private::SectionLoadList> SectionLoadListSP;
typedef std::shared_ptr<lldb_private::SearchFilter> SearchFilterSP;
typedef std::shared_ptr<lldb_private::Settings> SettingsSP;
+ typedef std::unique_ptr<lldb_private::SourceManager> SourceManagerUP;
typedef std::shared_ptr<lldb_private::StackFrame> StackFrameSP;
typedef std::unique_ptr<lldb_private::StackFrame> StackFrameUP;
typedef std::weak_ptr<lldb_private::StackFrame> StackFrameWP;
@@ -386,10 +397,12 @@ namespace lldb {
typedef std::shared_ptr<lldb_private::SymbolFileType> SymbolFileTypeSP;
typedef std::weak_ptr<lldb_private::SymbolFileType> SymbolFileTypeWP;
typedef std::shared_ptr<lldb_private::SymbolContextSpecifier> SymbolContextSpecifierSP;
+ typedef std::unique_ptr<lldb_private::SymbolVendor> SymbolVendorUP;
typedef std::shared_ptr<lldb_private::SyntheticChildren> SyntheticChildrenSP;
typedef std::shared_ptr<lldb_private::SyntheticChildrenFrontEnd> SyntheticChildrenFrontEndSP;
typedef std::shared_ptr<lldb_private::Target> TargetSP;
typedef std::weak_ptr<lldb_private::Target> TargetWP;
+ typedef std::shared_ptr<lldb_private::TargetProperties> TargetPropertiesSP;
typedef std::shared_ptr<lldb_private::Thread> ThreadSP;
typedef std::weak_ptr<lldb_private::Thread> ThreadWP;
typedef std::shared_ptr<lldb_private::ThreadCollection> ThreadCollectionSP;
@@ -419,7 +432,7 @@ namespace lldb {
typedef std::shared_ptr<lldb_private::VariableList> VariableListSP;
typedef std::shared_ptr<lldb_private::ValueObjectList> ValueObjectListSP;
typedef std::shared_ptr<lldb_private::Watchpoint> WatchpointSP;
-
+
} // namespace lldb
diff --git a/include/lldb/lldb-private-interfaces.h b/include/lldb/lldb-private-interfaces.h
index f35938ce17b7..7b5c1c9d2c05 100644
--- a/include/lldb/lldb-private-interfaces.h
+++ b/include/lldb/lldb-private-interfaces.h
@@ -29,6 +29,7 @@ namespace lldb_private
typedef EmulateInstruction * (*EmulateInstructionCreateInstance) (const ArchSpec &arch, InstructionType inst_type);
typedef OperatingSystem* (*OperatingSystemCreateInstance) (Process *process, bool force);
typedef LanguageRuntime *(*LanguageRuntimeCreateInstance) (Process *process, lldb::LanguageType language);
+ typedef lldb::CommandObjectSP (*LanguageRuntimeGetCommandObject) (CommandInterpreter& interpreter);
typedef SystemRuntime *(*SystemRuntimeCreateInstance) (Process *process);
typedef lldb::PlatformSP (*PlatformCreateInstance) (bool force, const ArchSpec *arch);
typedef lldb::ProcessSP (*ProcessCreateInstance) (Target &target, Listener &listener, const FileSpec *crash_file_path);
diff --git a/include/lldb/lldb-private-types.h b/include/lldb/lldb-private-types.h
index cd4867238ef9..cce637fce279 100644
--- a/include/lldb/lldb-private-types.h
+++ b/include/lldb/lldb-private-types.h
@@ -14,11 +14,22 @@
#include "lldb/lldb-private.h"
+namespace llvm
+{
+namespace sys
+{
+class DynamicLibrary;
+}
+}
+
namespace lldb_private
{
class Platform;
class ExecutionContext;
+ typedef llvm::sys::DynamicLibrary (*LoadPluginCallbackType)(const lldb::DebuggerSP &debugger_sp,
+ const FileSpec &spec, Error &error);
+
//----------------------------------------------------------------------
// Every register is described in detail including its name, alternate
// name (optional), encoding, size in bytes and the default display
diff --git a/include/lldb/lldb-private.h b/include/lldb/lldb-private.h
index bbd974303f1f..951b22fc94c5 100644
--- a/include/lldb/lldb-private.h
+++ b/include/lldb/lldb-private.h
@@ -23,66 +23,13 @@
#include "lldb/lldb-public.h"
#include "lldb/lldb-private-enumerations.h"
#include "lldb/lldb-private-interfaces.h"
-#include "lldb/lldb-private-log.h"
#include "lldb/lldb-private-types.h"
namespace lldb_private {
-//------------------------------------------------------------------
-/// Initializes lldb.
-///
-/// This function should be called prior to using any lldb
-/// classes to ensure they have a chance to do any static
-/// initialization that they need to do.
-//------------------------------------------------------------------
-void
-Initialize();
-
-
-//------------------------------------------------------------------
-/// Notifies any classes that lldb will be terminating soon.
-///
-/// This function will be called when the Debugger shared instance
-/// is being destructed and will give classes the ability to clean
-/// up any threads or other resources they have that they might not
-/// be able to clean up in their own destructors.
-///
-/// Internal classes that need this ability will need to add their
-/// void T::WillTerminate() method in the body of this function in
-/// lldb.cpp to ensure it will get called.
-///
-/// TODO: when we start having external plug-ins, we will need a way
-/// for plug-ins to register a WillTerminate callback.
-//------------------------------------------------------------------
-void
-WillTerminate();
-
-//------------------------------------------------------------------
-/// Terminates lldb
-///
-/// This function optionally can be called when clients are done
-/// using lldb functionality to free up any static resources
-/// that have been allocated during initialization or during
-/// function calls. No lldb functions should be called after
-/// calling this function without again calling DCInitialize()
-/// again.
-//------------------------------------------------------------------
-void
-Terminate();
-
-
const char *
GetVersion ();
-const char *
-GetVoteAsCString (Vote vote);
-
-const char *
-GetSectionTypeAsCString (lldb::SectionType sect_type);
-
-bool
-NameMatches (const char *name, NameMatchType match_type, const char *match);
-
} // namespace lldb_private
diff --git a/source/API/SBAddress.cpp b/source/API/SBAddress.cpp
index d6e32b60059b..f95fcb8b3985 100644
--- a/source/API/SBAddress.cpp
+++ b/source/API/SBAddress.cpp
@@ -14,7 +14,9 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/LineEntry.h"
#include "lldb/Target/Target.h"
diff --git a/source/API/SBAttachInfo.cpp b/source/API/SBAttachInfo.cpp
new file mode 100644
index 000000000000..07446df27dff
--- /dev/null
+++ b/source/API/SBAttachInfo.cpp
@@ -0,0 +1,242 @@
+//===-- SBAttachInfo.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBAttachInfo.h"
+
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBListener.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBAttachInfo::SBAttachInfo () :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+}
+
+SBAttachInfo::SBAttachInfo (lldb::pid_t pid) :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+ m_opaque_sp->SetProcessID (pid);
+}
+
+SBAttachInfo::SBAttachInfo (const char *path, bool wait_for) :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+ if (path && path[0])
+ m_opaque_sp->GetExecutableFile().SetFile(path, false);
+ m_opaque_sp->SetWaitForLaunch (wait_for);
+}
+
+SBAttachInfo::SBAttachInfo (const SBAttachInfo &rhs) :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+ *m_opaque_sp = *rhs.m_opaque_sp;
+}
+
+SBAttachInfo::~SBAttachInfo()
+{
+}
+
+lldb_private::ProcessAttachInfo &
+SBAttachInfo::ref ()
+{
+ return *m_opaque_sp;
+}
+
+SBAttachInfo &
+SBAttachInfo::operator = (const SBAttachInfo &rhs)
+{
+ if (this != &rhs)
+ *m_opaque_sp = *rhs.m_opaque_sp;
+ return *this;
+}
+
+lldb::pid_t
+SBAttachInfo::GetProcessID ()
+{
+ return m_opaque_sp->GetProcessID();
+}
+
+void
+SBAttachInfo::SetProcessID (lldb::pid_t pid)
+{
+ m_opaque_sp->SetProcessID (pid);
+}
+
+
+uint32_t
+SBAttachInfo::GetResumeCount ()
+{
+ return m_opaque_sp->GetResumeCount();
+}
+
+void
+SBAttachInfo::SetResumeCount (uint32_t c)
+{
+ m_opaque_sp->SetResumeCount (c);
+}
+
+const char *
+SBAttachInfo::GetProcessPluginName ()
+{
+ return m_opaque_sp->GetProcessPluginName();
+}
+
+void
+SBAttachInfo::SetProcessPluginName (const char *plugin_name)
+{
+ return m_opaque_sp->SetProcessPluginName (plugin_name);
+}
+
+void
+SBAttachInfo::SetExecutable (const char *path)
+{
+ if (path && path[0])
+ m_opaque_sp->GetExecutableFile().SetFile(path, false);
+ else
+ m_opaque_sp->GetExecutableFile().Clear();
+}
+
+void
+SBAttachInfo::SetExecutable (SBFileSpec exe_file)
+{
+ if (exe_file.IsValid())
+ m_opaque_sp->GetExecutableFile() = exe_file.ref();
+ else
+ m_opaque_sp->GetExecutableFile().Clear();
+}
+
+bool
+SBAttachInfo::GetWaitForLaunch ()
+{
+ return m_opaque_sp->GetWaitForLaunch();
+}
+
+void
+SBAttachInfo::SetWaitForLaunch (bool b)
+{
+ m_opaque_sp->SetWaitForLaunch (b);
+}
+
+bool
+SBAttachInfo::GetIgnoreExisting ()
+{
+ return m_opaque_sp->GetIgnoreExisting();
+}
+
+void
+SBAttachInfo::SetIgnoreExisting (bool b)
+{
+ m_opaque_sp->SetIgnoreExisting (b);
+}
+
+uint32_t
+SBAttachInfo::GetUserID()
+{
+ return m_opaque_sp->GetUserID();
+}
+
+uint32_t
+SBAttachInfo::GetGroupID()
+{
+ return m_opaque_sp->GetGroupID();
+}
+
+bool
+SBAttachInfo::UserIDIsValid ()
+{
+ return m_opaque_sp->UserIDIsValid();
+}
+
+bool
+SBAttachInfo::GroupIDIsValid ()
+{
+ return m_opaque_sp->GroupIDIsValid();
+}
+
+void
+SBAttachInfo::SetUserID (uint32_t uid)
+{
+ m_opaque_sp->SetUserID (uid);
+}
+
+void
+SBAttachInfo::SetGroupID (uint32_t gid)
+{
+ m_opaque_sp->SetGroupID (gid);
+}
+
+uint32_t
+SBAttachInfo::GetEffectiveUserID()
+{
+ return m_opaque_sp->GetEffectiveUserID();
+}
+
+uint32_t
+SBAttachInfo::GetEffectiveGroupID()
+{
+ return m_opaque_sp->GetEffectiveGroupID();
+}
+
+bool
+SBAttachInfo::EffectiveUserIDIsValid ()
+{
+ return m_opaque_sp->EffectiveUserIDIsValid();
+}
+
+bool
+SBAttachInfo::EffectiveGroupIDIsValid ()
+{
+ return m_opaque_sp->EffectiveGroupIDIsValid ();
+}
+
+void
+SBAttachInfo::SetEffectiveUserID (uint32_t uid)
+{
+ m_opaque_sp->SetEffectiveUserID(uid);
+}
+
+void
+SBAttachInfo::SetEffectiveGroupID (uint32_t gid)
+{
+ m_opaque_sp->SetEffectiveGroupID(gid);
+}
+
+lldb::pid_t
+SBAttachInfo::GetParentProcessID ()
+{
+ return m_opaque_sp->GetParentProcessID();
+}
+
+void
+SBAttachInfo::SetParentProcessID (lldb::pid_t pid)
+{
+ m_opaque_sp->SetParentProcessID (pid);
+}
+
+bool
+SBAttachInfo::ParentProcessIDIsValid()
+{
+ return m_opaque_sp->ParentProcessIDIsValid();
+}
+
+SBListener
+SBAttachInfo::GetListener ()
+{
+ return SBListener(m_opaque_sp->GetListener());
+}
+
+void
+SBAttachInfo::SetListener (SBListener &listener)
+{
+ m_opaque_sp->SetListener(listener.GetSP());
+}
diff --git a/source/API/SBCommandInterpreter.cpp b/source/API/SBCommandInterpreter.cpp
index 193d06e4d920..d901e728105b 100644
--- a/source/API/SBCommandInterpreter.cpp
+++ b/source/API/SBCommandInterpreter.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/lldb-types.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Core/Listener.h"
@@ -20,6 +18,7 @@
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBCommandReturnObject.h"
#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBEvent.h"
#include "lldb/API/SBExecutionContext.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBTarget.h"
@@ -446,6 +445,37 @@ SBCommandInterpreter::GetDebugger ()
return sb_debugger;
}
+bool
+SBCommandInterpreter::GetPromptOnQuit()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->GetPromptOnQuit();
+ return false;
+}
+
+void
+SBCommandInterpreter::SetPromptOnQuit (bool b)
+{
+ if (m_opaque_ptr)
+ m_opaque_ptr->SetPromptOnQuit(b);
+}
+
+void
+SBCommandInterpreter::ResolveCommand(const char *command_line, SBCommandReturnObject &result)
+{
+ result.Clear();
+ if (command_line && m_opaque_ptr)
+ {
+ m_opaque_ptr->ResolveCommand(command_line, result.ref());
+ }
+ else
+ {
+ result->AppendError("SBCommandInterpreter or the command line is not valid");
+ result->SetStatus(eReturnStatusFailed);
+ }
+}
+
+
CommandInterpreter *
SBCommandInterpreter::get ()
{
@@ -532,7 +562,7 @@ SBCommandInterpreter::GetBroadcaster ()
const char *
SBCommandInterpreter::GetBroadcasterClass ()
{
- return Communication::GetStaticBroadcasterClass().AsCString();
+ return CommandInterpreter::GetStaticBroadcasterClass().AsCString();
}
const char *
@@ -548,6 +578,12 @@ SBCommandInterpreter::GetArgumentDescriptionAsCString (const lldb::CommandArgume
}
bool
+SBCommandInterpreter::EventIsCommandInterpreterEvent (const lldb::SBEvent &event)
+{
+ return event.GetBroadcasterClass() == SBCommandInterpreter::GetBroadcasterClass();
+}
+
+bool
SBCommandInterpreter::SetCommandOverrideCallback (const char *command_name,
lldb::CommandOverrideCallback callback,
void *baton)
@@ -566,170 +602,6 @@ SBCommandInterpreter::SetCommandOverrideCallback (const char *command_name,
return false;
}
-#ifndef LLDB_DISABLE_PYTHON
-
-// Defined in the SWIG source file
-extern "C" void
-init_lldb(void);
-
-// these are the Pythonic implementations of the required callbacks
-// these are scripting-language specific, which is why they belong here
-// we still need to use function pointers to them instead of relying
-// on linkage-time resolution because the SWIG stuff and this file
-// get built at different times
-extern "C" bool
-LLDBSwigPythonBreakpointCallbackFunction (const char *python_function_name,
- const char *session_dictionary_name,
- const lldb::StackFrameSP& sb_frame,
- const lldb::BreakpointLocationSP& sb_bp_loc);
-
-extern "C" bool
-LLDBSwigPythonWatchpointCallbackFunction (const char *python_function_name,
- const char *session_dictionary_name,
- const lldb::StackFrameSP& sb_frame,
- const lldb::WatchpointSP& sb_wp);
-
-extern "C" bool
-LLDBSwigPythonCallTypeScript (const char *python_function_name,
- void *session_dictionary,
- const lldb::ValueObjectSP& valobj_sp,
- void** pyfunct_wrapper,
- const lldb::TypeSummaryOptionsSP& options_sp,
- std::string& retval);
-
-extern "C" void*
-LLDBSwigPythonCreateSyntheticProvider (const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::ValueObjectSP& valobj_sp);
-
-
-extern "C" void*
-LLDBSwigPythonCreateScriptedThreadPlan (const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::ThreadPlanSP& thread_plan_sp);
-
-extern "C" bool
-LLDBSWIGPythonCallThreadPlan (void *implementor,
- const char *method_name,
- Event *event_sp,
- bool &got_error);
-
-extern "C" uint32_t
-LLDBSwigPython_CalculateNumChildren (void *implementor);
-
-extern "C" void *
-LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx);
-
-extern "C" int
-LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name);
-
-extern "C" void *
-LLDBSWIGPython_CastPyObjectToSBValue (void* data);
-
-extern lldb::ValueObjectSP
-LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data);
-
-extern "C" bool
-LLDBSwigPython_UpdateSynthProviderInstance (void* implementor);
-
-extern "C" bool
-LLDBSwigPython_MightHaveChildrenSynthProviderInstance (void* implementor);
-
-extern "C" void *
-LLDBSwigPython_GetValueSynthProviderInstance (void* implementor);
-
-extern "C" bool
-LLDBSwigPythonCallCommand (const char *python_function_name,
- const char *session_dictionary_name,
- lldb::DebuggerSP& debugger,
- const char* args,
- lldb_private::CommandReturnObject &cmd_retobj,
- lldb::ExecutionContextRefSP exe_ctx_ref_sp);
-
-extern "C" bool
-LLDBSwigPythonCallModuleInit (const char *python_module_name,
- const char *session_dictionary_name,
- lldb::DebuggerSP& debugger);
-
-extern "C" void*
-LLDBSWIGPythonCreateOSPlugin (const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::ProcessSP& process_sp);
-
-extern "C" bool
-LLDBSWIGPythonRunScriptKeywordProcess (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::ProcessSP& process,
- std::string& output);
-
-extern "C" bool
-LLDBSWIGPythonRunScriptKeywordThread (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::ThreadSP& thread,
- std::string& output);
-
-extern "C" bool
-LLDBSWIGPythonRunScriptKeywordTarget (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::TargetSP& target,
- std::string& output);
-
-extern "C" bool
-LLDBSWIGPythonRunScriptKeywordFrame (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::StackFrameSP& frame,
- std::string& output);
-
-extern "C" bool
-LLDBSWIGPythonRunScriptKeywordValue (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::ValueObjectSP& value,
- std::string& output);
-
-extern "C" void*
-LLDBSWIGPython_GetDynamicSetting (void* module,
- const char* setting,
- const lldb::TargetSP& target_sp);
-
-
-#endif
-
-void
-SBCommandInterpreter::InitializeSWIG ()
-{
- static bool g_initialized = false;
- if (!g_initialized)
- {
- g_initialized = true;
-#ifndef LLDB_DISABLE_PYTHON
- ScriptInterpreter::InitializeInterpreter (init_lldb,
- LLDBSwigPythonBreakpointCallbackFunction,
- LLDBSwigPythonWatchpointCallbackFunction,
- LLDBSwigPythonCallTypeScript,
- LLDBSwigPythonCreateSyntheticProvider,
- LLDBSwigPython_CalculateNumChildren,
- LLDBSwigPython_GetChildAtIndex,
- LLDBSwigPython_GetIndexOfChildWithName,
- LLDBSWIGPython_CastPyObjectToSBValue,
- LLDBSWIGPython_GetValueObjectSPFromSBValue,
- LLDBSwigPython_UpdateSynthProviderInstance,
- LLDBSwigPython_MightHaveChildrenSynthProviderInstance,
- LLDBSwigPython_GetValueSynthProviderInstance,
- LLDBSwigPythonCallCommand,
- LLDBSwigPythonCallModuleInit,
- LLDBSWIGPythonCreateOSPlugin,
- LLDBSWIGPythonRunScriptKeywordProcess,
- LLDBSWIGPythonRunScriptKeywordThread,
- LLDBSWIGPythonRunScriptKeywordTarget,
- LLDBSWIGPythonRunScriptKeywordFrame,
- LLDBSWIGPythonRunScriptKeywordValue,
- LLDBSWIGPython_GetDynamicSetting,
- LLDBSwigPythonCreateScriptedThreadPlan,
- LLDBSWIGPythonCallThreadPlan);
-#endif
- }
-}
-
lldb::SBCommand
SBCommandInterpreter::AddMultiwordCommand (const char* name, const char* help)
{
@@ -780,6 +652,28 @@ SBCommand::GetHelp ()
return NULL;
}
+const char*
+SBCommand::GetHelpLong ()
+{
+ if (IsValid ())
+ return m_opaque_sp->GetHelpLong ();
+ return NULL;
+}
+
+void
+SBCommand::SetHelp (const char* help)
+{
+ if (IsValid())
+ m_opaque_sp->SetHelp(help);
+}
+
+void
+SBCommand::SetHelpLong (const char* help)
+{
+ if (IsValid())
+ m_opaque_sp->SetHelpLong(help);
+}
+
lldb::SBCommand
SBCommand::AddMultiwordCommand (const char* name, const char* help)
{
@@ -809,3 +703,17 @@ SBCommand::AddCommand (const char* name, lldb::SBCommandPluginInterface *impl, c
return lldb::SBCommand();
}
+uint32_t
+SBCommand::GetFlags ()
+{
+ if (!IsValid())
+ return 0;
+ return m_opaque_sp->GetFlags().Get();
+}
+
+void
+SBCommand::SetFlags (uint32_t flags)
+{
+ if (IsValid())
+ m_opaque_sp->GetFlags().Set(flags);
+}
diff --git a/source/API/SBDebugger.cpp b/source/API/SBDebugger.cpp
index a95f2ffc06d9..df2019f5a46b 100644
--- a/source/API/SBDebugger.cpp
+++ b/source/API/SBDebugger.cpp
@@ -7,12 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBDebugger.h"
#include "lldb/lldb-private.h"
+#include "lldb/API/SystemInitializerFull.h"
#include "lldb/API/SBListener.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBCommandInterpreter.h"
@@ -33,46 +32,24 @@
#include "lldb/API/SBTypeSummary.h"
#include "lldb/API/SBTypeSynthetic.h"
-
#include "lldb/Core/Debugger.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Initialization/SystemLifetimeManager.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/OptionGroupPlatform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/TargetList.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/DynamicLibrary.h"
using namespace lldb;
using namespace lldb_private;
-SBInputReader::SBInputReader()
-{
-}
-SBInputReader::~SBInputReader()
-{
-}
-
-SBError
-SBInputReader::Initialize(lldb::SBDebugger& sb_debugger, unsigned long (*)(void*, lldb::SBInputReader*, lldb::InputReaderAction, char const*, unsigned long), void*, lldb::InputReaderGranularity, char const*, char const*, bool)
-{
- return SBError();
-}
-
-void
-SBInputReader::SetIsDone(bool)
-{
-}
-bool
-SBInputReader::IsActive() const
-{
- return false;
-}
-
static llvm::sys::DynamicLibrary
LoadPlugin (const lldb::DebuggerSP &debugger_sp, const FileSpec& spec, Error& error)
{
@@ -107,6 +84,34 @@ LoadPlugin (const lldb::DebuggerSP &debugger_sp, const FileSpec& spec, Error& er
return llvm::sys::DynamicLibrary();
}
+static llvm::ManagedStatic<SystemLifetimeManager> g_debugger_lifetime;
+
+SBInputReader::SBInputReader()
+{
+}
+SBInputReader::~SBInputReader()
+{
+}
+
+SBError
+SBInputReader::Initialize(lldb::SBDebugger &sb_debugger,
+ unsigned long (*)(void *, lldb::SBInputReader *, lldb::InputReaderAction, char const *,
+ unsigned long),
+ void *, lldb::InputReaderGranularity, char const *, char const *, bool)
+{
+ return SBError();
+}
+
+void
+SBInputReader::SetIsDone(bool)
+{
+}
+bool
+SBInputReader::IsActive() const
+{
+ return false;
+}
+
void
SBDebugger::Initialize ()
{
@@ -115,15 +120,13 @@ SBDebugger::Initialize ()
if (log)
log->Printf ("SBDebugger::Initialize ()");
- SBCommandInterpreter::InitializeSWIG ();
-
- Debugger::Initialize(LoadPlugin);
+ g_debugger_lifetime->Initialize(llvm::make_unique<SystemInitializerFull>(), LoadPlugin);
}
void
SBDebugger::Terminate ()
{
- Debugger::Terminate();
+ g_debugger_lifetime->Terminate();
}
void
diff --git a/source/API/SBEvent.cpp b/source/API/SBEvent.cpp
index c62c495b87c8..164636defc9a 100644
--- a/source/API/SBEvent.cpp
+++ b/source/API/SBEvent.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBEvent.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBExpressionOptions.cpp b/source/API/SBExpressionOptions.cpp
index 448ff4cf6dd6..43b7d03064f5 100644
--- a/source/API/SBExpressionOptions.cpp
+++ b/source/API/SBExpressionOptions.cpp
@@ -185,6 +185,17 @@ SBExpressionOptions::SetSuppressPersistentResult (bool b)
return m_opaque_ap->SetResultIsInternal (b);
}
+const char *
+SBExpressionOptions::GetPrefix () const
+{
+ return m_opaque_ap->GetPrefix();
+}
+
+void
+SBExpressionOptions::SetPrefix (const char *prefix)
+{
+ return m_opaque_ap->SetPrefix(prefix);
+}
EvaluateExpressionOptions *
SBExpressionOptions::get() const
diff --git a/source/API/SBFileSpec.cpp b/source/API/SBFileSpec.cpp
index 8d63fc587d81..dd7435de1b5b 100644
--- a/source/API/SBFileSpec.cpp
+++ b/source/API/SBFileSpec.cpp
@@ -93,9 +93,8 @@ SBFileSpec::ResolvePath (const char *src_path, char *dst_path, size_t dst_len)
{
llvm::SmallString<64> result(src_path);
lldb_private::FileSpec::Resolve (result);
- size_t result_length = std::min(dst_len-1, result.size());
- ::strncpy(dst_path, result.c_str(), result_length + 1);
- return result_length;
+ ::snprintf(dst_path, dst_len, "%s", result.c_str());
+ return std::min(dst_len-1, result.size());
}
const char *
@@ -120,18 +119,19 @@ SBFileSpec::GetFilename() const
const char *
SBFileSpec::GetDirectory() const
{
- const char *s = m_opaque_ap->GetDirectory().AsCString();
+ FileSpec directory{*m_opaque_ap};
+ directory.GetFilename().Clear();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
{
- if (s)
+ if (directory)
log->Printf ("SBFileSpec(%p)::GetDirectory () => \"%s\"",
- static_cast<void*>(m_opaque_ap.get()), s);
+ static_cast<void*>(m_opaque_ap.get()), directory.GetCString());
else
log->Printf ("SBFileSpec(%p)::GetDirectory () => NULL",
static_cast<void*>(m_opaque_ap.get()));
}
- return s;
+ return directory.GetCString();
}
void
diff --git a/source/API/SBFrame.cpp b/source/API/SBFrame.cpp
index 325f40fd5b56..e845aef41f45 100644
--- a/source/API/SBFrame.cpp
+++ b/source/API/SBFrame.cpp
@@ -21,6 +21,7 @@
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObjectRegister.h"
#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
#include "lldb/Expression/ClangUserExpression.h"
#include "lldb/Host/Host.h"
#include "lldb/Symbol/Block.h"
@@ -44,6 +45,7 @@
#include "lldb/API/SBStream.h"
#include "lldb/API/SBSymbolContext.h"
#include "lldb/API/SBThread.h"
+#include "lldb/API/SBVariablesOptions.h"
using namespace lldb;
using namespace lldb_private;
@@ -452,6 +454,17 @@ SBFrame::GetFrameID () const
return frame_idx;
}
+lldb::addr_t
+SBFrame::GetCFA () const
+{
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame)
+ return frame->GetStackID().GetCallFrameAddress();
+ return LLDB_INVALID_ADDRESS;
+}
+
+
addr_t
SBFrame::GetPC () const
{
@@ -868,32 +881,30 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy
case eValueTypeVariableArgument: // function argument variables
case eValueTypeVariableLocal: // function local variables
{
- SymbolContext sc (frame->GetSymbolContext (eSymbolContextBlock));
+ SymbolContext sc(frame->GetSymbolContext(eSymbolContextBlock));
const bool can_create = true;
const bool get_parent_variables = true;
const bool stop_if_block_is_inlined_function = true;
- if (sc.block && sc.block->AppendVariables (can_create,
- get_parent_variables,
- stop_if_block_is_inlined_function,
- &variable_list))
+ if (sc.block)
+ sc.block->AppendVariables(can_create,
+ get_parent_variables,
+ stop_if_block_is_inlined_function,
+ &variable_list);
+ if (value_type == eValueTypeVariableGlobal)
{
- if (value_type == eValueTypeVariableGlobal)
- {
- const bool get_file_globals = true;
- VariableList* frame_vars = frame->GetVariableList(get_file_globals);
- if (frame_vars)
- frame_vars->AppendVariablesIfUnique(variable_list);
- }
- ConstString const_name(name);
- VariableSP variable_sp(variable_list.FindVariable(const_name,value_type));
- if (variable_sp)
- {
- value_sp = frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues);
- sb_value.SetSP (value_sp, use_dynamic);
- break;
- }
+ const bool get_file_globals = true;
+ VariableList *frame_vars = frame->GetVariableList(get_file_globals);
+ if (frame_vars)
+ frame_vars->AppendVariablesIfUnique(variable_list);
+ }
+ ConstString const_name(name);
+ VariableSP variable_sp(variable_list.FindVariable(const_name, value_type));
+ if (variable_sp)
+ {
+ value_sp = frame->GetValueObjectForFrameVariable(variable_sp, eNoDynamicValues);
+ sb_value.SetSP(value_sp, use_dynamic);
}
}
break;
@@ -1075,18 +1086,44 @@ SBFrame::GetVariables (bool arguments,
if (frame && target)
{
lldb::DynamicValueType use_dynamic = frame->CalculateTarget()->GetPreferDynamicValue();
- value_list = GetVariables (arguments, locals, statics, in_scope_only, use_dynamic);
+ const bool include_runtime_support_values = target ? target->GetDisplayRuntimeSupportValues() : false;
+
+ SBVariablesOptions options;
+ options.SetIncludeArguments(arguments);
+ options.SetIncludeLocals(locals);
+ options.SetIncludeStatics(statics);
+ options.SetInScopeOnly(in_scope_only);
+ options.SetIncludeRuntimeSupportValues(include_runtime_support_values);
+ options.SetUseDynamic(use_dynamic);
+
+ value_list = GetVariables (options);
}
return value_list;
}
-SBValueList
+lldb::SBValueList
SBFrame::GetVariables (bool arguments,
bool locals,
bool statics,
bool in_scope_only,
lldb::DynamicValueType use_dynamic)
{
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ Target *target = exe_ctx.GetTargetPtr();
+ const bool include_runtime_support_values = target ? target->GetDisplayRuntimeSupportValues() : false;
+ SBVariablesOptions options;
+ options.SetIncludeArguments(arguments);
+ options.SetIncludeLocals(locals);
+ options.SetIncludeStatics(statics);
+ options.SetInScopeOnly(in_scope_only);
+ options.SetIncludeRuntimeSupportValues(include_runtime_support_values);
+ options.SetUseDynamic(use_dynamic);
+ return GetVariables(options);
+}
+
+SBValueList
+SBFrame::GetVariables (const lldb::SBVariablesOptions& options)
+{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBValueList value_list;
@@ -1096,10 +1133,19 @@ SBFrame::GetVariables (bool arguments,
StackFrame *frame = NULL;
Target *target = exe_ctx.GetTargetPtr();
+ const bool statics = options.GetIncludeStatics();
+ const bool arguments = options.GetIncludeArguments();
+ const bool locals = options.GetIncludeLocals();
+ const bool in_scope_only = options.GetInScopeOnly();
+ const bool include_runtime_support_values = options.GetIncludeRuntimeSupportValues();
+ const lldb::DynamicValueType use_dynamic = options.GetUseDynamic();
+
if (log)
- log->Printf ("SBFrame::GetVariables (arguments=%i, locals=%i, statics=%i, in_scope_only=%i)",
- arguments, locals, statics, in_scope_only);
-
+ log->Printf ("SBFrame::GetVariables (arguments=%i, locals=%i, statics=%i, in_scope_only=%i runtime=%i dynamic=%i)",
+ arguments, locals,
+ statics, in_scope_only,
+ include_runtime_support_values, use_dynamic);
+
Process *process = exe_ctx.GetProcessPtr();
if (target && process)
{
@@ -1147,6 +1193,12 @@ SBFrame::GetVariables (bool arguments,
continue;
ValueObjectSP valobj_sp(frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues));
+
+ if (false == include_runtime_support_values &&
+ valobj_sp &&
+ true == valobj_sp->IsRuntimeSupportValue())
+ continue;
+
SBValue value_sb;
value_sb.SetSP(valobj_sp,use_dynamic);
value_list.Append(value_sb);
@@ -1449,6 +1501,12 @@ SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &option
bool
SBFrame::IsInlined()
{
+ return static_cast<const SBFrame*>(this)->IsInlined();
+}
+
+bool
+SBFrame::IsInlined() const
+{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
ExecutionContext exe_ctx(m_opaque_sp.get());
StackFrame *frame = NULL;
@@ -1486,6 +1544,12 @@ SBFrame::IsInlined()
const char *
SBFrame::GetFunctionName()
{
+ return static_cast<const SBFrame*>(this)->GetFunctionName();
+}
+
+const char *
+SBFrame::GetFunctionName() const
+{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
const char *name = NULL;
ExecutionContext exe_ctx(m_opaque_sp.get());
@@ -1538,4 +1602,3 @@ SBFrame::GetFunctionName()
}
return name;
}
-
diff --git a/source/API/SBInstruction.cpp b/source/API/SBInstruction.cpp
index 6158418d2f2a..36be94801863 100644
--- a/source/API/SBInstruction.cpp
+++ b/source/API/SBInstruction.cpp
@@ -180,7 +180,7 @@ SBInstruction::GetDescription (lldb::SBStream &s)
// didn't have a stream already created, one will get created...
FormatEntity::Entry format;
FormatEntity::Parse("${addr}: ", format);
- m_opaque_sp->Dump (&s.ref(), 0, true, false, NULL, &sc, NULL, &format);
+ m_opaque_sp->Dump (&s.ref(), 0, true, false, NULL, &sc, NULL, &format, 0);
return true;
}
return false;
@@ -202,7 +202,7 @@ SBInstruction::Print (FILE *out)
StreamFile out_stream (out, false);
FormatEntity::Entry format;
FormatEntity::Parse("${addr}: ", format);
- m_opaque_sp->Dump (&out_stream, 0, true, false, NULL, &sc, NULL, &format);
+ m_opaque_sp->Dump (&out_stream, 0, true, false, NULL, &sc, NULL, &format, 0);
}
}
diff --git a/source/API/SBInstructionList.cpp b/source/API/SBInstructionList.cpp
index 812824b4d2e5..34b0e05079f8 100644
--- a/source/API/SBInstructionList.cpp
+++ b/source/API/SBInstructionList.cpp
@@ -120,7 +120,7 @@ SBInstructionList::GetDescription (lldb::SBStream &description)
module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
}
- inst->Dump (&sref, max_opcode_byte_size, true, false, NULL, &sc, &prev_sc, &format);
+ inst->Dump (&sref, max_opcode_byte_size, true, false, NULL, &sc, &prev_sc, &format, 0);
sref.EOL();
}
return true;
diff --git a/source/API/SBLanguageRuntime.cpp b/source/API/SBLanguageRuntime.cpp
new file mode 100644
index 000000000000..93a54cd76dff
--- /dev/null
+++ b/source/API/SBLanguageRuntime.cpp
@@ -0,0 +1,26 @@
+//===-- SBLanguageRuntime.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBLanguageRuntime.h"
+#include "lldb/Target/LanguageRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+lldb::LanguageType
+SBLanguageRuntime::GetLanguageTypeFromString (const char *string)
+{
+ return LanguageRuntime::GetLanguageTypeFromString(string);
+}
+
+const char *
+SBLanguageRuntime::GetNameForLanguageType (lldb::LanguageType language)
+{
+ return LanguageRuntime::GetNameForLanguageType(language);
+}
diff --git a/source/API/SBLaunchInfo.cpp b/source/API/SBLaunchInfo.cpp
index dcb0e1b488ba..54bed8799b8b 100644
--- a/source/API/SBLaunchInfo.cpp
+++ b/source/API/SBLaunchInfo.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBLaunchInfo.h"
#include "lldb/API/SBFileSpec.h"
@@ -36,6 +34,12 @@ SBLaunchInfo::ref ()
return *m_opaque_sp;
}
+const lldb_private::ProcessLaunchInfo &
+SBLaunchInfo::ref () const
+{
+ return *m_opaque_sp;
+}
+
lldb::pid_t
SBLaunchInfo::GetProcessID()
{
@@ -169,13 +173,13 @@ SBLaunchInfo::Clear ()
const char *
SBLaunchInfo::GetWorkingDirectory () const
{
- return m_opaque_sp->GetWorkingDirectory();
+ return m_opaque_sp->GetWorkingDirectory().GetCString();
}
void
SBLaunchInfo::SetWorkingDirectory (const char *working_dir)
{
- m_opaque_sp->SetWorkingDirectory(working_dir);
+ m_opaque_sp->SetWorkingDirectory(FileSpec{working_dir, false});
}
uint32_t
@@ -217,6 +221,18 @@ SBLaunchInfo::SetShell (const char * path)
m_opaque_sp->SetShell (FileSpec(path, false));
}
+bool
+SBLaunchInfo::GetShellExpandArguments ()
+{
+ return m_opaque_sp->GetShellExpandArguments();
+}
+
+void
+SBLaunchInfo::SetShellExpandArguments (bool expand)
+{
+ m_opaque_sp->SetShellExpandArguments(expand);
+}
+
uint32_t
SBLaunchInfo::GetResumeCount ()
{
@@ -244,7 +260,7 @@ SBLaunchInfo::AddDuplicateFileAction (int fd, int dup_fd)
bool
SBLaunchInfo::AddOpenFileAction (int fd, const char *path, bool read, bool write)
{
- return m_opaque_sp->AppendOpenFileAction(fd, path, read, write);
+ return m_opaque_sp->AppendOpenFileAction(fd, FileSpec{path, false}, read, write);
}
bool
diff --git a/source/API/SBListener.cpp b/source/API/SBListener.cpp
index 87318739a3a4..643c82d70f78 100644
--- a/source/API/SBListener.cpp
+++ b/source/API/SBListener.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBListener.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBDebugger.h"
diff --git a/source/API/SBModule.cpp b/source/API/SBModule.cpp
index 0d7dda1aa1f7..0249a7edcd2b 100644
--- a/source/API/SBModule.cpp
+++ b/source/API/SBModule.cpp
@@ -20,6 +20,7 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectList.h"
#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/Symtab.h"
@@ -211,34 +212,28 @@ SBModule::GetUUIDString () const
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
- static char uuid_string_buffer[80];
- const char *uuid_c_string = NULL;
- std::string uuid_string;
+ const char *uuid_cstr = NULL;
ModuleSP module_sp (GetSP ());
if (module_sp)
- uuid_string = module_sp->GetUUID().GetAsString();
-
- if (!uuid_string.empty())
{
- strncpy (uuid_string_buffer, uuid_string.c_str(), sizeof (uuid_string_buffer));
- uuid_string_buffer[sizeof (uuid_string_buffer) - 1] = '\0';
- uuid_c_string = uuid_string_buffer;
+ // We are going to return a "const char *" value through the public
+ // API, so we need to constify it so it gets added permanently the
+ // string pool and then we don't need to worry about the lifetime of the
+ // string as it will never go away once it has been put into the ConstString
+ // string pool
+ uuid_cstr = ConstString(module_sp->GetUUID().GetAsString()).GetCString();
}
- if (log)
+ if (uuid_cstr && uuid_cstr[0])
{
- if (!uuid_string.empty())
- {
- StreamString s;
- module_sp->GetUUID().Dump (&s);
- log->Printf ("SBModule(%p)::GetUUIDString () => %s",
- static_cast<void*>(module_sp.get()), s.GetData());
- }
- else
- log->Printf ("SBModule(%p)::GetUUIDString () => NULL",
- static_cast<void*>(module_sp.get()));
+ if (log)
+ log->Printf ("SBModule(%p)::GetUUIDString () => %s", static_cast<void*>(module_sp.get()), uuid_cstr);
+ return uuid_cstr;
}
- return uuid_c_string;
+
+ if (log)
+ log->Printf ("SBModule(%p)::GetUUIDString () => NULL", static_cast<void*>(module_sp.get()));
+ return NULL;
}
@@ -690,3 +685,30 @@ SBModule::GetVersion (uint32_t *versions, uint32_t num_versions)
}
}
+lldb::SBFileSpec
+SBModule::GetSymbolFileSpec() const
+{
+ lldb::SBFileSpec sb_file_spec;
+ ModuleSP module_sp(GetSP());
+ if (module_sp)
+ {
+ SymbolVendor *symbol_vendor_ptr = module_sp->GetSymbolVendor();
+ if (symbol_vendor_ptr)
+ sb_file_spec.SetFileSpec(symbol_vendor_ptr->GetMainFileSpec());
+ }
+ return sb_file_spec;
+}
+
+lldb::SBAddress
+SBModule::GetObjectFileHeaderAddress() const
+{
+ lldb::SBAddress sb_addr;
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ ObjectFile *objfile_ptr = module_sp->GetObjectFile();
+ if (objfile_ptr)
+ sb_addr.ref() = objfile_ptr->GetHeaderAddress();
+ }
+ return sb_addr;
+}
diff --git a/source/API/SBPlatform.cpp b/source/API/SBPlatform.cpp
index b23891d39c21..5662f36b514d 100644
--- a/source/API/SBPlatform.cpp
+++ b/source/API/SBPlatform.cpp
@@ -329,9 +329,9 @@ SBPlatform::SetWorkingDirectory(const char *path)
if (platform_sp)
{
if (path)
- platform_sp->SetWorkingDirectory(ConstString(path));
+ platform_sp->SetWorkingDirectory(FileSpec{path, false});
else
- platform_sp->SetWorkingDirectory(ConstString());
+ platform_sp->SetWorkingDirectory(FileSpec{});
return true;
}
return false;
@@ -378,7 +378,7 @@ SBPlatform::GetTriple()
PlatformSP platform_sp(GetSP());
if (platform_sp)
{
- ArchSpec arch(platform_sp->GetRemoteSystemArchitecture());
+ ArchSpec arch(platform_sp->GetSystemArchitecture());
if (arch.IsValid())
{
// Const-ify the string so we don't need to worry about the lifetime of the string
@@ -545,7 +545,7 @@ SBPlatform::Run (SBPlatformShellCommand &shell_command)
shell_command.SetWorkingDirectory(working_dir);
}
return platform_sp->RunShellCommand(command,
- working_dir,
+ FileSpec{working_dir, false},
&shell_command.m_opaque_ptr->m_status,
&shell_command.m_opaque_ptr->m_signo,
&shell_command.m_opaque_ptr->m_output,
@@ -598,7 +598,7 @@ SBPlatform::MakeDirectory (const char *path, uint32_t file_permissions)
PlatformSP platform_sp(GetSP());
if (platform_sp)
{
- sb_error.ref() = platform_sp->MakeDirectory(path, file_permissions);
+ sb_error.ref() = platform_sp->MakeDirectory(FileSpec{path, false}, file_permissions);
}
else
{
@@ -614,7 +614,7 @@ SBPlatform::GetFilePermissions (const char *path)
if (platform_sp)
{
uint32_t file_permissions = 0;
- platform_sp->GetFilePermissions(path, file_permissions);
+ platform_sp->GetFilePermissions(FileSpec{path, false}, file_permissions);
return file_permissions;
}
return 0;
@@ -628,7 +628,7 @@ SBPlatform::SetFilePermissions (const char *path, uint32_t file_permissions)
PlatformSP platform_sp(GetSP());
if (platform_sp)
{
- sb_error.ref() = platform_sp->SetFilePermissions(path, file_permissions);
+ sb_error.ref() = platform_sp->SetFilePermissions(FileSpec{path, false}, file_permissions);
}
else
{
diff --git a/source/API/SBProcess.cpp b/source/API/SBProcess.cpp
index 9a0b23bc93d2..a1dbf686da03 100644
--- a/source/API/SBProcess.cpp
+++ b/source/API/SBProcess.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBProcess.h"
// C Includes
@@ -169,11 +167,11 @@ SBProcess::RemoteLaunch (char const **argv,
{
if (stop_at_entry)
launch_flags |= eLaunchFlagStopAtEntry;
- ProcessLaunchInfo launch_info (stdin_path,
- stdout_path,
- stderr_path,
- working_directory,
- launch_flags);
+ ProcessLaunchInfo launch_info(FileSpec{stdin_path, false},
+ FileSpec{stdout_path, false},
+ FileSpec{stderr_path, false},
+ FileSpec{working_directory, false},
+ launch_flags);
Module *exe_module = process_sp->GetTarget().GetExecutableModulePointer();
if (exe_module)
launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
@@ -603,6 +601,30 @@ SBProcess::GetStopID(bool include_expression_stops)
return 0;
}
+SBEvent
+SBProcess::GetStopEventForStopID(uint32_t stop_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBEvent sb_event;
+ EventSP event_sp;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ event_sp = process_sp->GetStopEventForStopID(stop_id);
+ sb_event.reset(event_sp);
+ }
+
+ if (log)
+ log->Printf ("SBProcess(%p)::GetStopEventForStopID (stop_id=%" PRIu32 ") => SBEvent(%p)",
+ static_cast<void*>(process_sp.get()),
+ stop_id,
+ static_cast<void*>(event_sp.get()));
+
+ return sb_event;
+}
+
StateType
SBProcess::GetState ()
{
@@ -768,7 +790,7 @@ SBProcess::Destroy ()
if (process_sp)
{
Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
- sb_error.SetError(process_sp->Destroy());
+ sb_error.SetError(process_sp->Destroy(false));
}
else
sb_error.SetErrorString ("SBProcess is invalid");
@@ -821,7 +843,7 @@ SBProcess::Kill ()
if (process_sp)
{
Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
- sb_error.SetError (process_sp->Destroy());
+ sb_error.SetError (process_sp->Destroy(true));
}
else
sb_error.SetErrorString ("SBProcess is invalid");
@@ -918,9 +940,9 @@ SBProcess::GetThreadByID (tid_t tid)
ProcessSP process_sp(GetSP());
if (process_sp)
{
- Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
Process::StopLocker stop_locker;
const bool can_update = stop_locker.TryLock(&process_sp->GetRunLock());
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
thread_sp = process_sp->GetThreadList().FindThreadByID (tid, can_update);
sb_thread.SetThread (thread_sp);
}
@@ -942,9 +964,9 @@ SBProcess::GetThreadByIndexID (uint32_t index_id)
ProcessSP process_sp(GetSP());
if (process_sp)
{
- Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
Process::StopLocker stop_locker;
const bool can_update = stop_locker.TryLock(&process_sp->GetRunLock());
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
thread_sp = process_sp->GetThreadList().FindThreadByIndexID (index_id, can_update);
sb_thread.SetThread (thread_sp);
}
@@ -999,9 +1021,15 @@ SBProcess::GetProcessFromEvent (const SBEvent &event)
}
bool
+SBProcess::GetInterruptedFromEvent (const SBEvent &event)
+{
+ return Process::ProcessEventData::GetInterruptedFromEvent(event.get());
+}
+
+bool
SBProcess::EventIsProcessEvent (const SBEvent &event)
{
- return strcmp (event.GetBroadcasterClass(), SBProcess::GetBroadcasterClass()) == 0;
+ return event.GetBroadcasterClass() == SBProcess::GetBroadcasterClass();
}
SBBroadcaster
diff --git a/source/API/SBQueue.cpp b/source/API/SBQueue.cpp
index b19ed72543c2..be4c5fda1540 100644
--- a/source/API/SBQueue.cpp
+++ b/source/API/SBQueue.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include <inttypes.h>
#include "lldb/API/SBQueue.h"
diff --git a/source/API/SBQueueItem.cpp b/source/API/SBQueueItem.cpp
index 6a1aa7bec61a..e7a199b9f0b4 100644
--- a/source/API/SBQueueItem.cpp
+++ b/source/API/SBQueueItem.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
#include "lldb/lldb-forward.h"
#include "lldb/API/SBAddress.h"
diff --git a/source/API/SBSourceManager.cpp b/source/API/SBSourceManager.cpp
index 0b8cbfceda0f..8196b91d00b3 100644
--- a/source/API/SBSourceManager.cpp
+++ b/source/API/SBSourceManager.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBSourceManager.h"
#include "lldb/API/SBTarget.h"
diff --git a/source/API/SBSymbol.cpp b/source/API/SBSymbol.cpp
index 12a3b317d501..246a455d93a7 100644
--- a/source/API/SBSymbol.cpp
+++ b/source/API/SBSymbol.cpp
@@ -137,10 +137,11 @@ SBSymbol::GetInstructions (SBTarget target, const char *flavor_string)
}
if (m_opaque_ptr->ValueIsAddress())
{
- ModuleSP module_sp (m_opaque_ptr->GetAddress().GetModule());
+ const Address &symbol_addr = m_opaque_ptr->GetAddressRef();
+ ModuleSP module_sp = symbol_addr.GetModule();
if (module_sp)
{
- AddressRange symbol_range (m_opaque_ptr->GetAddress(), m_opaque_ptr->GetByteSize());
+ AddressRange symbol_range (symbol_addr, m_opaque_ptr->GetByteSize());
const bool prefer_file_cache = false;
sb_instructions.SetDisassembler (Disassembler::DisassembleRange (module_sp->GetArchitecture (),
NULL,
@@ -172,7 +173,7 @@ SBSymbol::GetStartAddress ()
SBAddress addr;
if (m_opaque_ptr && m_opaque_ptr->ValueIsAddress())
{
- addr.SetAddress (&m_opaque_ptr->GetAddress());
+ addr.SetAddress (&m_opaque_ptr->GetAddressRef());
}
return addr;
}
@@ -186,7 +187,7 @@ SBSymbol::GetEndAddress ()
lldb::addr_t range_size = m_opaque_ptr->GetByteSize();
if (range_size > 0)
{
- addr.SetAddress (&m_opaque_ptr->GetAddress());
+ addr.SetAddress (&m_opaque_ptr->GetAddressRef());
addr->Slide (m_opaque_ptr->GetByteSize());
}
}
diff --git a/source/API/SBTarget.cpp b/source/API/SBTarget.cpp
index b13d8289560f..923885223a5f 100644
--- a/source/API/SBTarget.cpp
+++ b/source/API/SBTarget.cpp
@@ -7,14 +7,13 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTarget.h"
#include "lldb/lldb-public.h"
-#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBBreakpoint.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBEvent.h"
#include "lldb/API/SBExpressionOptions.h"
#include "lldb/API/SBFileSpec.h"
#include "lldb/API/SBListener.h"
@@ -47,12 +46,16 @@
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/DeclVendor.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
-
+#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
@@ -66,230 +69,31 @@ using namespace lldb_private;
#define DEFAULT_DISASM_BYTE_SIZE 32
+namespace {
-SBAttachInfo::SBAttachInfo () :
- m_opaque_sp (new ProcessAttachInfo())
-{
-}
-
-SBAttachInfo::SBAttachInfo (lldb::pid_t pid) :
- m_opaque_sp (new ProcessAttachInfo())
-{
- m_opaque_sp->SetProcessID (pid);
-}
-
-SBAttachInfo::SBAttachInfo (const char *path, bool wait_for) :
- m_opaque_sp (new ProcessAttachInfo())
-{
- if (path && path[0])
- m_opaque_sp->GetExecutableFile().SetFile(path, false);
- m_opaque_sp->SetWaitForLaunch (wait_for);
-}
-
-SBAttachInfo::SBAttachInfo (const SBAttachInfo &rhs) :
- m_opaque_sp (new ProcessAttachInfo())
-{
- *m_opaque_sp = *rhs.m_opaque_sp;
-}
-
-SBAttachInfo::~SBAttachInfo()
-{
-}
-
-lldb_private::ProcessAttachInfo &
-SBAttachInfo::ref ()
-{
- return *m_opaque_sp;
-}
-
-SBAttachInfo &
-SBAttachInfo::operator = (const SBAttachInfo &rhs)
-{
- if (this != &rhs)
- *m_opaque_sp = *rhs.m_opaque_sp;
- return *this;
-}
-
-lldb::pid_t
-SBAttachInfo::GetProcessID ()
-{
- return m_opaque_sp->GetProcessID();
-}
-
-void
-SBAttachInfo::SetProcessID (lldb::pid_t pid)
-{
- m_opaque_sp->SetProcessID (pid);
-}
-
-
-uint32_t
-SBAttachInfo::GetResumeCount ()
-{
- return m_opaque_sp->GetResumeCount();
-}
-
-void
-SBAttachInfo::SetResumeCount (uint32_t c)
-{
- m_opaque_sp->SetResumeCount (c);
-}
-
-const char *
-SBAttachInfo::GetProcessPluginName ()
-{
- return m_opaque_sp->GetProcessPluginName();
-}
-
-void
-SBAttachInfo::SetProcessPluginName (const char *plugin_name)
-{
- return m_opaque_sp->SetProcessPluginName (plugin_name);
-}
-
-void
-SBAttachInfo::SetExecutable (const char *path)
-{
- if (path && path[0])
- m_opaque_sp->GetExecutableFile().SetFile(path, false);
- else
- m_opaque_sp->GetExecutableFile().Clear();
-}
-
-void
-SBAttachInfo::SetExecutable (SBFileSpec exe_file)
-{
- if (exe_file.IsValid())
- m_opaque_sp->GetExecutableFile() = exe_file.ref();
- else
- m_opaque_sp->GetExecutableFile().Clear();
-}
-
-bool
-SBAttachInfo::GetWaitForLaunch ()
-{
- return m_opaque_sp->GetWaitForLaunch();
-}
-
-void
-SBAttachInfo::SetWaitForLaunch (bool b)
-{
- m_opaque_sp->SetWaitForLaunch (b);
-}
-
-bool
-SBAttachInfo::GetIgnoreExisting ()
-{
- return m_opaque_sp->GetIgnoreExisting();
-}
-
-void
-SBAttachInfo::SetIgnoreExisting (bool b)
-{
- m_opaque_sp->SetIgnoreExisting (b);
-}
-
-uint32_t
-SBAttachInfo::GetUserID()
-{
- return m_opaque_sp->GetUserID();
-}
-
-uint32_t
-SBAttachInfo::GetGroupID()
-{
- return m_opaque_sp->GetGroupID();
-}
-
-bool
-SBAttachInfo::UserIDIsValid ()
-{
- return m_opaque_sp->UserIDIsValid();
-}
-
-bool
-SBAttachInfo::GroupIDIsValid ()
-{
- return m_opaque_sp->GroupIDIsValid();
-}
-
-void
-SBAttachInfo::SetUserID (uint32_t uid)
-{
- m_opaque_sp->SetUserID (uid);
-}
-
-void
-SBAttachInfo::SetGroupID (uint32_t gid)
-{
- m_opaque_sp->SetGroupID (gid);
-}
-
-uint32_t
-SBAttachInfo::GetEffectiveUserID()
-{
- return m_opaque_sp->GetEffectiveUserID();
-}
-
-uint32_t
-SBAttachInfo::GetEffectiveGroupID()
-{
- return m_opaque_sp->GetEffectiveGroupID();
-}
-
-bool
-SBAttachInfo::EffectiveUserIDIsValid ()
-{
- return m_opaque_sp->EffectiveUserIDIsValid();
-}
-
-bool
-SBAttachInfo::EffectiveGroupIDIsValid ()
-{
- return m_opaque_sp->EffectiveGroupIDIsValid ();
-}
-
-void
-SBAttachInfo::SetEffectiveUserID (uint32_t uid)
-{
- m_opaque_sp->SetEffectiveUserID(uid);
-}
-
-void
-SBAttachInfo::SetEffectiveGroupID (uint32_t gid)
-{
- m_opaque_sp->SetEffectiveGroupID(gid);
-}
-
-lldb::pid_t
-SBAttachInfo::GetParentProcessID ()
-{
- return m_opaque_sp->GetParentProcessID();
-}
-
-void
-SBAttachInfo::SetParentProcessID (lldb::pid_t pid)
+Error
+AttachToProcess (ProcessAttachInfo &attach_info, Target &target)
{
- m_opaque_sp->SetParentProcessID (pid);
-}
+ Mutex::Locker api_locker (target.GetAPIMutex ());
-bool
-SBAttachInfo::ParentProcessIDIsValid()
-{
- return m_opaque_sp->ParentProcessIDIsValid();
-}
+ auto process_sp = target.GetProcessSP ();
+ if (process_sp)
+ {
+ const auto state = process_sp->GetState ();
+ if (process_sp->IsAlive () && state == eStateConnected)
+ {
+ // If we are already connected, then we have already specified the
+ // listener, so if a valid listener is supplied, we need to error out
+ // to let the client know.
+ if (attach_info.GetListener ())
+ return Error ("process is connected and already has a listener, pass empty listener");
+ }
+ }
-SBListener
-SBAttachInfo::GetListener ()
-{
- return SBListener(m_opaque_sp->GetListener());
+ return target.Attach (attach_info, nullptr);
}
-void
-SBAttachInfo::SetListener (SBListener &listener)
-{
- m_opaque_sp->SetListener(listener.GetSP());
-}
+} // namespace
//----------------------------------------------------------------------
// SBTarget constructor
@@ -324,6 +128,32 @@ SBTarget::~SBTarget()
{
}
+bool
+SBTarget::EventIsTargetEvent (const SBEvent &event)
+{
+ return Target::TargetEventData::GetEventDataFromEvent(event.get()) != NULL;
+}
+
+SBTarget
+SBTarget::GetTargetFromEvent (const SBEvent &event)
+{
+ return Target::TargetEventData::GetTargetFromEvent (event.get());
+}
+
+uint32_t
+SBTarget::GetNumModulesFromEvent (const SBEvent &event)
+{
+ const ModuleList module_list = Target::TargetEventData::GetModuleListFromEvent (event.get());
+ return module_list.GetSize();
+}
+
+SBModule
+SBTarget::GetModuleAtIndexFromEvent (const uint32_t idx, const SBEvent &event)
+{
+ const ModuleList module_list = Target::TargetEventData::GetModuleListFromEvent (event.get());
+ return SBModule(module_list.GetModuleAtIndex(idx));
+}
+
const char *
SBTarget::GetBroadcasterClassName ()
{
@@ -513,7 +343,11 @@ SBTarget::Launch
if (getenv("LLDB_LAUNCH_FLAG_DISABLE_STDIO"))
launch_flags |= eLaunchFlagDisableSTDIO;
- ProcessLaunchInfo launch_info (stdin_path, stdout_path, stderr_path, working_directory, launch_flags);
+ ProcessLaunchInfo launch_info(FileSpec{stdin_path, false},
+ FileSpec{stdout_path, false},
+ FileSpec{stderr_path, false},
+ FileSpec{working_directory, false},
+ launch_flags);
Module *exe_module = target_sp->GetExecutableModulePointer();
if (exe_module)
@@ -613,7 +447,6 @@ SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBProcess sb_process;
- ProcessSP process_sp;
TargetSP target_sp(GetSP());
if (log)
@@ -622,72 +455,34 @@ SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error)
if (target_sp)
{
- Mutex::Locker api_locker (target_sp->GetAPIMutex());
-
- StateType state = eStateInvalid;
- process_sp = target_sp->GetProcessSP();
- if (process_sp)
+ ProcessAttachInfo &attach_info = sb_attach_info.ref();
+ if (attach_info.ProcessIDIsValid() && !attach_info.UserIDIsValid())
{
- state = process_sp->GetState();
-
- if (process_sp->IsAlive() && state != eStateConnected)
+ PlatformSP platform_sp = target_sp->GetPlatform();
+ // See if we can pre-verify if a process exists or not
+ if (platform_sp && platform_sp->IsConnected())
{
- if (state == eStateAttaching)
- error.SetErrorString ("process attach is in progress");
+ lldb::pid_t attach_pid = attach_info.GetProcessID();
+ ProcessInstanceInfo instance_info;
+ if (platform_sp->GetProcessInfo(attach_pid, instance_info))
+ {
+ attach_info.SetUserID(instance_info.GetEffectiveUserID());
+ }
else
- error.SetErrorString ("a process is already being debugged");
- if (log)
- log->Printf ("SBTarget(%p)::Attach (...) => error %s",
- static_cast<void*>(target_sp.get()),
- error.GetCString());
- return sb_process;
- }
- }
-
- if (state != eStateConnected)
- process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
-
- if (process_sp)
- {
- ProcessAttachInfo &attach_info = sb_attach_info.ref();
- if (attach_info.ProcessIDIsValid() && !attach_info.UserIDIsValid())
- {
- PlatformSP platform_sp = target_sp->GetPlatform();
- // See if we can pre-verify if a process exists or not
- if (platform_sp && platform_sp->IsConnected())
{
- lldb::pid_t attach_pid = attach_info.GetProcessID();
- ProcessInstanceInfo instance_info;
- if (platform_sp->GetProcessInfo(attach_pid, instance_info))
+ error.ref().SetErrorStringWithFormat("no process found with process ID %" PRIu64, attach_pid);
+ if (log)
{
- attach_info.SetUserID(instance_info.GetEffectiveUserID());
- }
- else
- {
- error.ref().SetErrorStringWithFormat("no process found with process ID %" PRIu64, attach_pid);
- if (log)
- {
- log->Printf ("SBTarget(%p)::Attach (...) => error %s",
- static_cast<void*>(target_sp.get()), error.GetCString());
- }
- return sb_process;
+ log->Printf ("SBTarget(%p)::Attach (...) => error %s",
+ static_cast<void*>(target_sp.get()), error.GetCString());
}
+ return sb_process;
}
}
- error.SetError (process_sp->Attach (attach_info));
- if (error.Success())
- {
- sb_process.SetSP (process_sp);
- // If we are doing synchronous mode, then wait for the
- // process to stop!
- if (target_sp->GetDebugger().GetAsyncExecution () == false)
- process_sp->WaitForProcessToStop (NULL);
- }
- }
- else
- {
- error.SetErrorString ("unable to create lldb_private::Process");
}
+ error.SetError(AttachToProcess(attach_info, *target_sp));
+ if (error.Success())
+ sb_process.SetSP(target_sp->GetProcessSP());
}
else
{
@@ -697,7 +492,7 @@ SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error)
if (log)
log->Printf ("SBTarget(%p)::Attach (...) => SBProcess(%p)",
static_cast<void*>(target_sp.get()),
- static_cast<void*>(process_sp.get()));
+ static_cast<void*>(sb_process.GetSP().get()));
return sb_process;
}
@@ -726,87 +521,37 @@ SBTarget::AttachToProcessWithID
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBProcess sb_process;
- ProcessSP process_sp;
TargetSP target_sp(GetSP());
if (log)
- log->Printf ("SBTarget(%p)::AttachToProcessWithID (listener, pid=%" PRId64 ", error)...",
- static_cast<void*>(target_sp.get()), pid);
+ log->Printf ("SBTarget(%p)::%s (listener, pid=%" PRId64 ", error)...",
+ static_cast<void*>(target_sp.get()),
+ __FUNCTION__,
+ pid);
if (target_sp)
{
- Mutex::Locker api_locker (target_sp->GetAPIMutex());
-
- StateType state = eStateInvalid;
- process_sp = target_sp->GetProcessSP();
- if (process_sp)
- {
- state = process_sp->GetState();
-
- if (process_sp->IsAlive() && state != eStateConnected)
- {
- if (state == eStateAttaching)
- error.SetErrorString ("process attach is in progress");
- else
- error.SetErrorString ("a process is already being debugged");
- return sb_process;
- }
- }
-
- if (state == eStateConnected)
- {
- // If we are already connected, then we have already specified the
- // listener, so if a valid listener is supplied, we need to error out
- // to let the client know.
- if (listener.IsValid())
- {
- error.SetErrorString ("process is connected and already has a listener, pass empty listener");
- return sb_process;
- }
- }
- else
- {
- if (listener.IsValid())
- process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL);
- else
- process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
- }
- if (process_sp)
- {
- sb_process.SetSP (process_sp);
+ ProcessAttachInfo attach_info;
+ attach_info.SetProcessID (pid);
+ if (listener.IsValid())
+ attach_info.SetListener(listener.GetSP());
- ProcessAttachInfo attach_info;
- attach_info.SetProcessID (pid);
+ ProcessInstanceInfo instance_info;
+ if (target_sp->GetPlatform ()->GetProcessInfo (pid, instance_info))
+ attach_info.SetUserID (instance_info.GetEffectiveUserID ());
- PlatformSP platform_sp = target_sp->GetPlatform();
- ProcessInstanceInfo instance_info;
- if (platform_sp->GetProcessInfo(pid, instance_info))
- {
- attach_info.SetUserID(instance_info.GetEffectiveUserID());
- }
- error.SetError (process_sp->Attach (attach_info));
- if (error.Success())
- {
- // If we are doing synchronous mode, then wait for the
- // process to stop!
- if (target_sp->GetDebugger().GetAsyncExecution () == false)
- process_sp->WaitForProcessToStop (NULL);
- }
- }
- else
- {
- error.SetErrorString ("unable to create lldb_private::Process");
- }
+ error.SetError (AttachToProcess (attach_info, *target_sp));
+ if (error.Success ())
+ sb_process.SetSP (target_sp->GetProcessSP ());
}
else
- {
error.SetErrorString ("SBTarget is invalid");
- }
if (log)
- log->Printf ("SBTarget(%p)::AttachToProcessWithID (...) => SBProcess(%p)",
- static_cast<void*>(target_sp.get()),
- static_cast<void*>(process_sp.get()));
+ log->Printf ("SBTarget(%p)::%s (...) => SBProcess(%p)",
+ static_cast<void*>(target_sp.get ()),
+ __FUNCTION__,
+ static_cast<void*>(sb_process.GetSP().get ()));
return sb_process;
}
@@ -822,82 +567,35 @@ SBTarget::AttachToProcessWithName
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBProcess sb_process;
- ProcessSP process_sp;
TargetSP target_sp(GetSP());
if (log)
- log->Printf ("SBTarget(%p)::AttachToProcessWithName (listener, name=%s, wait_for=%s, error)...",
- static_cast<void*>(target_sp.get()), name,
+ log->Printf ("SBTarget(%p)::%s (listener, name=%s, wait_for=%s, error)...",
+ static_cast<void*>(target_sp.get()),
+ __FUNCTION__,
+ name,
wait_for ? "true" : "false");
if (name && target_sp)
{
- Mutex::Locker api_locker (target_sp->GetAPIMutex());
-
- StateType state = eStateInvalid;
- process_sp = target_sp->GetProcessSP();
- if (process_sp)
- {
- state = process_sp->GetState();
-
- if (process_sp->IsAlive() && state != eStateConnected)
- {
- if (state == eStateAttaching)
- error.SetErrorString ("process attach is in progress");
- else
- error.SetErrorString ("a process is already being debugged");
- return sb_process;
- }
- }
-
- if (state == eStateConnected)
- {
- // If we are already connected, then we have already specified the
- // listener, so if a valid listener is supplied, we need to error out
- // to let the client know.
- if (listener.IsValid())
- {
- error.SetErrorString ("process is connected and already has a listener, pass empty listener");
- return sb_process;
- }
- }
- else
- {
- if (listener.IsValid())
- process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL);
- else
- process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
- }
+ ProcessAttachInfo attach_info;
+ attach_info.GetExecutableFile().SetFile(name, false);
+ attach_info.SetWaitForLaunch(wait_for);
+ if (listener.IsValid())
+ attach_info.SetListener(listener.GetSP());
- if (process_sp)
- {
- sb_process.SetSP (process_sp);
- ProcessAttachInfo attach_info;
- attach_info.GetExecutableFile().SetFile(name, false);
- attach_info.SetWaitForLaunch(wait_for);
- error.SetError (process_sp->Attach (attach_info));
- if (error.Success())
- {
- // If we are doing synchronous mode, then wait for the
- // process to stop!
- if (target_sp->GetDebugger().GetAsyncExecution () == false)
- process_sp->WaitForProcessToStop (NULL);
- }
- }
- else
- {
- error.SetErrorString ("unable to create lldb_private::Process");
- }
+ error.SetError (AttachToProcess (attach_info, *target_sp));
+ if (error.Success ())
+ sb_process.SetSP (target_sp->GetProcessSP ());
}
else
- {
error.SetErrorString ("SBTarget is invalid");
- }
if (log)
- log->Printf ("SBTarget(%p)::AttachToPorcessWithName (...) => SBProcess(%p)",
+ log->Printf ("SBTarget(%p)::%s (...) => SBProcess(%p)",
static_cast<void*>(target_sp.get()),
- static_cast<void*>(process_sp.get()));
+ __FUNCTION__,
+ static_cast<void*>(sb_process.GetSP().get()));
return sb_process;
}
@@ -1112,7 +810,8 @@ SBTarget::BreakpointCreateByLocation (const SBFileSpec &sb_file_spec,
const LazyBool skip_prologue = eLazyBoolCalculate;
const bool internal = false;
const bool hardware = false;
- *sb_bp = target_sp->CreateBreakpoint (NULL, *sb_file_spec, line, check_inlines, skip_prologue, internal, hardware);
+ const LazyBool move_to_nearest_code = eLazyBoolCalculate;
+ *sb_bp = target_sp->CreateBreakpoint (NULL, *sb_file_spec, line, check_inlines, skip_prologue, internal, hardware, move_to_nearest_code);
}
if (log)
@@ -1359,6 +1058,7 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
RegularExpression regexp(source_regex);
FileSpecList source_file_spec_list;
const bool hardware = false;
+ const LazyBool move_to_nearest_code = eLazyBoolCalculate;
source_file_spec_list.Append (source_file.ref());
if (module_name && module_name[0])
@@ -1366,11 +1066,11 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
FileSpecList module_spec_list;
module_spec_list.Append (FileSpec (module_name, false));
- *sb_bp = target_sp->CreateSourceRegexBreakpoint (&module_spec_list, &source_file_spec_list, regexp, false, hardware);
+ *sb_bp = target_sp->CreateSourceRegexBreakpoint (&module_spec_list, &source_file_spec_list, regexp, false, hardware, move_to_nearest_code);
}
else
{
- *sb_bp = target_sp->CreateSourceRegexBreakpoint (NULL, &source_file_spec_list, regexp, false, hardware);
+ *sb_bp = target_sp->CreateSourceRegexBreakpoint (NULL, &source_file_spec_list, regexp, false, hardware, move_to_nearest_code);
}
}
@@ -1387,9 +1087,9 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
}
lldb::SBBreakpoint
-SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
- const SBFileSpecList &module_list,
- const lldb::SBFileSpecList &source_file_list)
+SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
+ const SBFileSpecList &module_list,
+ const lldb::SBFileSpecList &source_file_list)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
@@ -1399,8 +1099,9 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
const bool hardware = false;
+ const LazyBool move_to_nearest_code = eLazyBoolCalculate;
RegularExpression regexp(source_regex);
- *sb_bp = target_sp->CreateSourceRegexBreakpoint (module_list.get(), source_file_list.get(), regexp, false, hardware);
+ *sb_bp = target_sp->CreateSourceRegexBreakpoint (module_list.get(), source_file_list.get(), regexp, false, hardware, move_to_nearest_code);
}
if (log)
@@ -2679,3 +2380,20 @@ SBTarget::GetStackRedZoneSize()
return 0;
}
+lldb::SBLaunchInfo
+SBTarget::GetLaunchInfo () const
+{
+ lldb::SBLaunchInfo launch_info(NULL);
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ launch_info.ref() = m_opaque_sp->GetProcessLaunchInfo();
+ return launch_info;
+}
+
+void
+SBTarget::SetLaunchInfo (const lldb::SBLaunchInfo &launch_info)
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ m_opaque_sp->SetProcessLaunchInfo(launch_info.ref());
+}
diff --git a/source/API/SBThread.cpp b/source/API/SBThread.cpp
index 9fe0d029496c..dfc7ce9629f3 100644
--- a/source/API/SBThread.cpp
+++ b/source/API/SBThread.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBThread.h"
#include "lldb/API/SBSymbolContext.h"
@@ -20,13 +18,15 @@
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StructuredData.h"
+#include "lldb/Core/ValueObject.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Queue.h"
-#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/UnixSignals.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlan.h"
@@ -114,13 +114,13 @@ SBThread::GetQueue () const
else
{
if (log)
- log->Printf ("SBThread(%p)::GetQueueKind() => error: process is running",
+ log->Printf ("SBThread(%p)::GetQueue() => error: process is running",
static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
if (log)
- log->Printf ("SBThread(%p)::GetQueueKind () => SBQueue(%p)",
+ log->Printf ("SBThread(%p)::GetQueue () => SBQueue(%p)",
static_cast<void*>(exe_ctx.GetThreadPtr()), static_cast<void*>(queue_sp.get()));
return sb_queue;
diff --git a/source/API/SBThreadPlan.cpp b/source/API/SBThreadPlan.cpp
index 02b1a8d893b6..2fcd72149409 100644
--- a/source/API/SBThreadPlan.cpp
+++ b/source/API/SBThreadPlan.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBThread.h"
#include "lldb/API/SBSymbolContext.h"
diff --git a/source/API/SBTypeCategory.cpp b/source/API/SBTypeCategory.cpp
index 66cf46236c65..ee9553ca6abd 100644
--- a/source/API/SBTypeCategory.cpp
+++ b/source/API/SBTypeCategory.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeCategory.h"
#include "lldb/API/SBTypeFilter.h"
diff --git a/source/API/SBTypeFilter.cpp b/source/API/SBTypeFilter.cpp
index 605e92de6991..8af3e1ff8641 100644
--- a/source/API/SBTypeFilter.cpp
+++ b/source/API/SBTypeFilter.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeFilter.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBTypeFormat.cpp b/source/API/SBTypeFormat.cpp
index d3ec9bc00bd0..9548fe904cdc 100644
--- a/source/API/SBTypeFormat.cpp
+++ b/source/API/SBTypeFormat.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeFormat.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBTypeNameSpecifier.cpp b/source/API/SBTypeNameSpecifier.cpp
index 3d03c6a0c539..c58747170b5a 100644
--- a/source/API/SBTypeNameSpecifier.cpp
+++ b/source/API/SBTypeNameSpecifier.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeNameSpecifier.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBTypeSummary.cpp b/source/API/SBTypeSummary.cpp
index 8a235bf50080..2c114545419c 100644
--- a/source/API/SBTypeSummary.cpp
+++ b/source/API/SBTypeSummary.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeSummary.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBTypeSynthetic.cpp b/source/API/SBTypeSynthetic.cpp
index 681ed6c032ab..6f9951dc5559 100644
--- a/source/API/SBTypeSynthetic.cpp
+++ b/source/API/SBTypeSynthetic.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeSynthetic.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp
index edecb93944ad..ef62c30e42cf 100644
--- a/source/API/SBValue.cpp
+++ b/source/API/SBValue.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBValue.h"
#include "lldb/API/SBDeclaration.h"
@@ -63,13 +61,19 @@ public:
lldb::DynamicValueType use_dynamic,
bool use_synthetic,
const char *name = NULL) :
- m_valobj_sp(in_valobj_sp),
+ m_valobj_sp(),
m_use_dynamic(use_dynamic),
m_use_synthetic(use_synthetic),
m_name (name)
{
- if (!m_name.IsEmpty() && m_valobj_sp)
- m_valobj_sp->SetName(m_name);
+ if (in_valobj_sp)
+ {
+ if ( (m_valobj_sp = in_valobj_sp->GetQualifiedRepresentationIfAvailable(lldb::eNoDynamicValues, false)) )
+ {
+ if (!m_name.IsEmpty())
+ m_valobj_sp->SetName(m_name);
+ }
+ }
}
ValueImpl (const ValueImpl& rhs) :
@@ -152,10 +156,20 @@ public:
return ValueObjectSP();
}
- if (value_sp->GetDynamicValue(m_use_dynamic))
- value_sp = value_sp->GetDynamicValue(m_use_dynamic);
- if (value_sp->GetSyntheticValue(m_use_synthetic))
- value_sp = value_sp->GetSyntheticValue(m_use_synthetic);
+ if (m_use_dynamic != eNoDynamicValues)
+ {
+ ValueObjectSP dynamic_sp = value_sp->GetDynamicValue(m_use_dynamic);
+ if (dynamic_sp)
+ value_sp = dynamic_sp;
+ }
+
+ if (m_use_synthetic)
+ {
+ ValueObjectSP synthetic_sp = value_sp->GetSyntheticValue(m_use_synthetic);
+ if (synthetic_sp)
+ value_sp = synthetic_sp;
+ }
+
if (!value_sp)
error.SetErrorString("invalid value object");
if (!m_name.IsEmpty())
@@ -969,14 +983,7 @@ SBValue::GetChildAtIndex (uint32_t idx, lldb::DynamicValueType use_dynamic, bool
child_sp = value_sp->GetChildAtIndex (idx, can_create);
if (can_create_synthetic && !child_sp)
{
- if (value_sp->IsPointerType())
- {
- child_sp = value_sp->GetSyntheticArrayMemberFromPointer(idx, can_create);
- }
- else if (value_sp->IsArrayType())
- {
- child_sp = value_sp->GetSyntheticArrayMemberFromArray(idx, can_create);
- }
+ child_sp = value_sp->GetSyntheticArrayMember(idx, can_create);
}
}
@@ -1244,6 +1251,22 @@ SBValue::MightHaveChildren ()
return has_children;
}
+bool
+SBValue::IsRuntimeSupportValue ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ bool is_support = false;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ is_support = value_sp->IsRuntimeSupportValue();
+
+ if (log)
+ log->Printf ("SBValue(%p)::IsRuntimeSupportValue() => %i",
+ static_cast<void*>(value_sp.get()), is_support);
+ return is_support;
+}
+
uint32_t
SBValue::GetNumChildren ()
{
diff --git a/source/API/SBVariablesOptions.cpp b/source/API/SBVariablesOptions.cpp
new file mode 100644
index 000000000000..7c453567c0ae
--- /dev/null
+++ b/source/API/SBVariablesOptions.cpp
@@ -0,0 +1,254 @@
+//===-- SBVariablesOptions.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lldb/API/SBVariablesOptions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class VariablesOptionsImpl
+{
+public:
+ VariablesOptionsImpl () :
+ m_include_arguments(false),
+ m_include_locals(false),
+ m_include_statics(false),
+ m_in_scope_only(false),
+ m_include_runtime_support_values(false),
+ m_use_dynamic(lldb::eNoDynamicValues)
+ {}
+
+ VariablesOptionsImpl (const VariablesOptionsImpl&) = default;
+
+ ~VariablesOptionsImpl () = default;
+
+ VariablesOptionsImpl&
+ operator = (const VariablesOptionsImpl&) = default;
+
+ bool
+ GetIncludeArguments () const
+ {
+ return m_include_arguments;
+ }
+
+ void
+ SetIncludeArguments (bool b)
+ {
+ m_include_arguments = b;
+ }
+
+ bool
+ GetIncludeLocals () const
+ {
+ return m_include_locals;
+ }
+
+ void
+ SetIncludeLocals (bool b)
+ {
+ m_include_locals = b;
+ }
+
+ bool
+ GetIncludeStatics () const
+ {
+ return m_include_statics;
+ }
+
+ void
+ SetIncludeStatics (bool b)
+ {
+ m_include_statics = b;
+ }
+
+ bool
+ GetInScopeOnly () const
+ {
+ return m_in_scope_only;
+ }
+
+ void
+ SetInScopeOnly (bool b)
+ {
+ m_in_scope_only = b;
+ }
+
+ bool
+ GetIncludeRuntimeSupportValues () const
+ {
+ return m_include_runtime_support_values;
+ }
+
+ void
+ SetIncludeRuntimeSupportValues (bool b)
+ {
+ m_include_runtime_support_values = b;
+ }
+
+ lldb::DynamicValueType
+ GetUseDynamic () const
+ {
+ return m_use_dynamic;
+ }
+
+ void
+ SetUseDynamic (lldb::DynamicValueType d)
+ {
+ m_use_dynamic = d;
+ }
+
+
+private:
+ bool m_include_arguments : 1;
+ bool m_include_locals : 1;
+ bool m_include_statics : 1;
+ bool m_in_scope_only : 1;
+ bool m_include_runtime_support_values : 1;
+ lldb::DynamicValueType m_use_dynamic;
+};
+
+SBVariablesOptions::SBVariablesOptions () :
+m_opaque_ap(new VariablesOptionsImpl())
+{
+}
+
+SBVariablesOptions::SBVariablesOptions (const SBVariablesOptions& options) :
+m_opaque_ap(new VariablesOptionsImpl(options.ref()))
+{
+}
+
+SBVariablesOptions&
+SBVariablesOptions::operator = (const SBVariablesOptions& options)
+{
+ m_opaque_ap.reset(new VariablesOptionsImpl(options.ref()));
+ return *this;
+}
+
+SBVariablesOptions::~SBVariablesOptions () = default;
+
+bool
+SBVariablesOptions::IsValid () const
+{
+ return m_opaque_ap.get() != nullptr;
+}
+
+bool
+SBVariablesOptions::GetIncludeArguments () const
+{
+ return m_opaque_ap->GetIncludeArguments();
+}
+
+void
+SBVariablesOptions::SetIncludeArguments (bool arguments)
+{
+ m_opaque_ap->SetIncludeArguments(arguments);
+}
+
+bool
+SBVariablesOptions::GetIncludeLocals () const
+{
+ return m_opaque_ap->GetIncludeLocals();
+}
+
+void
+SBVariablesOptions::SetIncludeLocals (bool locals)
+{
+ m_opaque_ap->SetIncludeLocals(locals);
+}
+
+bool
+SBVariablesOptions::GetIncludeStatics () const
+{
+ return m_opaque_ap->GetIncludeStatics();
+}
+
+void
+SBVariablesOptions::SetIncludeStatics (bool statics)
+{
+ m_opaque_ap->SetIncludeStatics(statics);
+}
+
+bool
+SBVariablesOptions::GetInScopeOnly () const
+{
+ return m_opaque_ap->GetInScopeOnly();
+}
+
+void
+SBVariablesOptions::SetInScopeOnly (bool in_scope_only)
+{
+ m_opaque_ap->SetInScopeOnly(in_scope_only);
+}
+
+bool
+SBVariablesOptions::GetIncludeRuntimeSupportValues () const
+{
+ return m_opaque_ap->GetIncludeRuntimeSupportValues();
+}
+
+void
+SBVariablesOptions::SetIncludeRuntimeSupportValues (bool runtime_support_values)
+{
+ m_opaque_ap->SetIncludeRuntimeSupportValues(runtime_support_values);
+}
+
+lldb::DynamicValueType
+SBVariablesOptions::GetUseDynamic () const
+{
+ return m_opaque_ap->GetUseDynamic();
+}
+
+void
+SBVariablesOptions::SetUseDynamic (lldb::DynamicValueType dynamic)
+{
+ m_opaque_ap->SetUseDynamic(dynamic);
+}
+
+VariablesOptionsImpl *
+SBVariablesOptions::operator->()
+{
+ return m_opaque_ap.operator->();
+}
+
+const VariablesOptionsImpl *
+SBVariablesOptions::operator->() const
+{
+ return m_opaque_ap.operator->();
+}
+
+VariablesOptionsImpl *
+SBVariablesOptions::get ()
+{
+ return m_opaque_ap.get();
+}
+
+VariablesOptionsImpl &
+SBVariablesOptions::ref()
+{
+ return *m_opaque_ap;
+}
+
+const VariablesOptionsImpl &
+SBVariablesOptions::ref() const
+{
+ return *m_opaque_ap;
+}
+
+SBVariablesOptions::SBVariablesOptions (VariablesOptionsImpl *lldb_object_ptr) :
+m_opaque_ap(std::move(lldb_object_ptr))
+{
+}
+
+void
+SBVariablesOptions::SetOptions (VariablesOptionsImpl *lldb_object_ptr)
+{
+ m_opaque_ap.reset(std::move(lldb_object_ptr));
+}
+
diff --git a/source/API/SystemInitializerFull.cpp b/source/API/SystemInitializerFull.cpp
new file mode 100644
index 000000000000..731d38a37bee
--- /dev/null
+++ b/source/API/SystemInitializerFull.cpp
@@ -0,0 +1,392 @@
+//===-- SystemInitializerFull.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SystemInitializerFull.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Initialization/SystemInitializerCommon.h"
+
+#include "Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h"
+#include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h"
+#include "Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h"
+#include "Plugins/ABI/SysV-arm/ABISysV_arm.h"
+#include "Plugins/ABI/SysV-arm64/ABISysV_arm64.h"
+#include "Plugins/ABI/SysV-i386/ABISysV_i386.h"
+#include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h"
+#include "Plugins/ABI/SysV-ppc/ABISysV_ppc.h"
+#include "Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h"
+#include "Plugins/ABI/SysV-mips/ABISysV_mips.h"
+#include "Plugins/ABI/SysV-mips64/ABISysV_mips64.h"
+#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h"
+#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
+#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
+#include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h"
+#include "Plugins/JITLoader/GDB/JITLoaderGDB.h"
+#include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h"
+#include "Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h"
+#include "Plugins/MemoryHistory/asan/MemoryHistoryASan.h"
+#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h"
+#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
+#include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
+#include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h"
+#include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h"
+#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
+
+#if defined(__APPLE__)
+#include "Plugins/Process/mach-core/ProcessMachCore.h"
+#include "Plugins/Process/MacOSX-Kernel/ProcessKDP.h"
+#include "Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h"
+#endif
+
+#if defined(__FreeBSD__)
+#include "Plugins/Process/FreeBSD/ProcessFreeBSD.h"
+#endif
+
+#if defined(_MSC_VER)
+#include "lldb/Host/windows/windows.h"
+#include "Plugins/Process/Windows/DynamicLoaderWindows.h"
+#include "Plugins/Process/Windows/ProcessWindows.h"
+#endif
+
+#if !defined(LLDB_DISABLE_PYTHON)
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+#endif
+
+#include "llvm/Support/TargetSelect.h"
+
+#include <string>
+
+using namespace lldb_private;
+
+#ifndef LLDB_DISABLE_PYTHON
+
+// Defined in the SWIG source file
+extern "C" void
+init_lldb(void);
+
+// these are the Pythonic implementations of the required callbacks
+// these are scripting-language specific, which is why they belong here
+// we still need to use function pointers to them instead of relying
+// on linkage-time resolution because the SWIG stuff and this file
+// get built at different times
+extern "C" bool
+LLDBSwigPythonBreakpointCallbackFunction (const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::StackFrameSP& sb_frame,
+ const lldb::BreakpointLocationSP& sb_bp_loc);
+
+extern "C" bool
+LLDBSwigPythonWatchpointCallbackFunction (const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::StackFrameSP& sb_frame,
+ const lldb::WatchpointSP& sb_wp);
+
+extern "C" bool
+LLDBSwigPythonCallTypeScript (const char *python_function_name,
+ void *session_dictionary,
+ const lldb::ValueObjectSP& valobj_sp,
+ void** pyfunct_wrapper,
+ const lldb::TypeSummaryOptionsSP& options_sp,
+ std::string& retval);
+
+extern "C" void*
+LLDBSwigPythonCreateSyntheticProvider (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ValueObjectSP& valobj_sp);
+
+extern "C" void*
+LLDBSwigPythonCreateCommandObject (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::DebuggerSP debugger_sp);
+
+extern "C" void*
+LLDBSwigPythonCreateScriptedThreadPlan (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ThreadPlanSP& thread_plan_sp);
+
+extern "C" bool
+LLDBSWIGPythonCallThreadPlan (void *implementor,
+ const char *method_name,
+ Event *event_sp,
+ bool &got_error);
+
+extern "C" size_t
+LLDBSwigPython_CalculateNumChildren (void *implementor);
+
+extern "C" void *
+LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx);
+
+extern "C" int
+LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name);
+
+extern "C" void *
+LLDBSWIGPython_CastPyObjectToSBValue (void* data);
+
+extern lldb::ValueObjectSP
+LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data);
+
+extern "C" bool
+LLDBSwigPython_UpdateSynthProviderInstance (void* implementor);
+
+extern "C" bool
+LLDBSwigPython_MightHaveChildrenSynthProviderInstance (void* implementor);
+
+extern "C" void *
+LLDBSwigPython_GetValueSynthProviderInstance (void* implementor);
+
+extern "C" bool
+LLDBSwigPythonCallCommand (const char *python_function_name,
+ const char *session_dictionary_name,
+ lldb::DebuggerSP& debugger,
+ const char* args,
+ lldb_private::CommandReturnObject &cmd_retobj,
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp);
+
+extern "C" bool
+LLDBSwigPythonCallCommandObject (void *implementor,
+ lldb::DebuggerSP& debugger,
+ const char* args,
+ lldb_private::CommandReturnObject& cmd_retobj,
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp);
+
+extern "C" bool
+LLDBSwigPythonCallModuleInit (const char *python_module_name,
+ const char *session_dictionary_name,
+ lldb::DebuggerSP& debugger);
+
+extern "C" void*
+LLDBSWIGPythonCreateOSPlugin (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ProcessSP& process_sp);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordProcess (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ProcessSP& process,
+ std::string& output);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordThread (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ThreadSP& thread,
+ std::string& output);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordTarget (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::TargetSP& target,
+ std::string& output);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordFrame (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::StackFrameSP& frame,
+ std::string& output);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordValue (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ValueObjectSP& value,
+ std::string& output);
+
+extern "C" void*
+LLDBSWIGPython_GetDynamicSetting (void* module,
+ const char* setting,
+ const lldb::TargetSP& target_sp);
+
+
+#endif
+
+SystemInitializerFull::SystemInitializerFull()
+{
+}
+
+SystemInitializerFull::~SystemInitializerFull()
+{
+}
+
+void
+SystemInitializerFull::Initialize()
+{
+ InitializeSWIG();
+
+ SystemInitializerCommon::Initialize();
+
+ // Initialize LLVM and Clang
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllDisassemblers();
+
+ ABIMacOSX_i386::Initialize();
+ ABIMacOSX_arm::Initialize();
+ ABIMacOSX_arm64::Initialize();
+ ABISysV_arm::Initialize();
+ ABISysV_arm64::Initialize();
+ ABISysV_i386::Initialize();
+ ABISysV_x86_64::Initialize();
+ ABISysV_ppc::Initialize();
+ ABISysV_ppc64::Initialize();
+ ABISysV_mips::Initialize();
+ ABISysV_mips64::Initialize();
+ DisassemblerLLVMC::Initialize();
+
+ JITLoaderGDB::Initialize();
+ ProcessElfCore::Initialize();
+ MemoryHistoryASan::Initialize();
+ AddressSanitizerRuntime::Initialize();
+
+ SymbolVendorELF::Initialize();
+ SymbolFileDWARF::Initialize();
+ SymbolFileSymtab::Initialize();
+ UnwindAssemblyInstEmulation::Initialize();
+ UnwindAssembly_x86::Initialize();
+ EmulateInstructionARM64::Initialize();
+ SymbolFileDWARFDebugMap::Initialize();
+ ItaniumABILanguageRuntime::Initialize();
+ AppleObjCRuntimeV2::Initialize();
+ AppleObjCRuntimeV1::Initialize();
+ SystemRuntimeMacOSX::Initialize();
+ RenderScriptRuntime::Initialize();
+
+#if defined(_MSC_VER)
+ DynamicLoaderWindows::Initialize();
+ ProcessWindows::Initialize();
+#endif
+#if defined(__FreeBSD__)
+ ProcessFreeBSD::Initialize();
+#endif
+#if defined(__APPLE__)
+ SymbolVendorMacOSX::Initialize();
+ ProcessKDP::Initialize();
+ ProcessMachCore::Initialize();
+#endif
+ //----------------------------------------------------------------------
+ // Platform agnostic plugins
+ //----------------------------------------------------------------------
+ platform_gdb_server::PlatformRemoteGDBServer::Initialize();
+
+ process_gdb_remote::ProcessGDBRemote::Initialize();
+ DynamicLoaderStatic::Initialize();
+
+ // Scan for any system or user LLDB plug-ins
+ PluginManager::Initialize();
+
+ // The process settings need to know about installed plug-ins, so the Settings must be initialized
+ // AFTER PluginManager::Initialize is called.
+
+ Debugger::SettingsInitialize();
+}
+
+void SystemInitializerFull::InitializeSWIG()
+{
+#if !defined(LLDB_DISABLE_PYTHON)
+ ScriptInterpreterPython::InitializeInterpreter(
+ init_lldb,
+ LLDBSwigPythonBreakpointCallbackFunction,
+ LLDBSwigPythonWatchpointCallbackFunction,
+ LLDBSwigPythonCallTypeScript,
+ LLDBSwigPythonCreateSyntheticProvider,
+ LLDBSwigPythonCreateCommandObject,
+ LLDBSwigPython_CalculateNumChildren,
+ LLDBSwigPython_GetChildAtIndex,
+ LLDBSwigPython_GetIndexOfChildWithName,
+ LLDBSWIGPython_CastPyObjectToSBValue,
+ LLDBSWIGPython_GetValueObjectSPFromSBValue,
+ LLDBSwigPython_UpdateSynthProviderInstance,
+ LLDBSwigPython_MightHaveChildrenSynthProviderInstance,
+ LLDBSwigPython_GetValueSynthProviderInstance,
+ LLDBSwigPythonCallCommand,
+ LLDBSwigPythonCallCommandObject,
+ LLDBSwigPythonCallModuleInit,
+ LLDBSWIGPythonCreateOSPlugin,
+ LLDBSWIGPythonRunScriptKeywordProcess,
+ LLDBSWIGPythonRunScriptKeywordThread,
+ LLDBSWIGPythonRunScriptKeywordTarget,
+ LLDBSWIGPythonRunScriptKeywordFrame,
+ LLDBSWIGPythonRunScriptKeywordValue,
+ LLDBSWIGPython_GetDynamicSetting,
+ LLDBSwigPythonCreateScriptedThreadPlan,
+ LLDBSWIGPythonCallThreadPlan);
+#endif
+}
+
+void
+SystemInitializerFull::Terminate()
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ Debugger::SettingsTerminate();
+
+ // Terminate and unload and loaded system or user LLDB plug-ins
+ PluginManager::Terminate();
+ ABIMacOSX_i386::Terminate();
+ ABIMacOSX_arm::Terminate();
+ ABIMacOSX_arm64::Terminate();
+ ABISysV_arm::Terminate();
+ ABISysV_arm64::Terminate();
+ ABISysV_i386::Terminate();
+ ABISysV_x86_64::Terminate();
+ ABISysV_ppc::Terminate();
+ ABISysV_ppc64::Terminate();
+ ABISysV_mips::Terminate();
+ ABISysV_mips64::Terminate();
+ DisassemblerLLVMC::Terminate();
+
+ JITLoaderGDB::Terminate();
+ ProcessElfCore::Terminate();
+ MemoryHistoryASan::Terminate();
+ AddressSanitizerRuntime::Terminate();
+ SymbolVendorELF::Terminate();
+ SymbolFileDWARF::Terminate();
+ SymbolFileSymtab::Terminate();
+ UnwindAssembly_x86::Terminate();
+ UnwindAssemblyInstEmulation::Terminate();
+ EmulateInstructionARM64::Terminate();
+ SymbolFileDWARFDebugMap::Terminate();
+ ItaniumABILanguageRuntime::Terminate();
+ AppleObjCRuntimeV2::Terminate();
+ AppleObjCRuntimeV1::Terminate();
+ SystemRuntimeMacOSX::Terminate();
+ RenderScriptRuntime::Terminate();
+
+#if defined(__APPLE__)
+ ProcessMachCore::Terminate();
+ ProcessKDP::Terminate();
+ SymbolVendorMacOSX::Terminate();
+#endif
+#if defined(_MSC_VER)
+ DynamicLoaderWindows::Terminate();
+#endif
+
+#if defined(__FreeBSD__)
+ ProcessFreeBSD::Terminate();
+#endif
+ Debugger::SettingsTerminate();
+
+ platform_gdb_server::PlatformRemoteGDBServer::Terminate();
+ process_gdb_remote::ProcessGDBRemote::Terminate();
+ DynamicLoaderStatic::Terminate();
+
+ // Now shutdown the common parts, in reverse order.
+ SystemInitializerCommon::Terminate();
+}
+
+void SystemInitializerFull::TerminateSWIG()
+{
+
+}
diff --git a/source/Breakpoint/Breakpoint.cpp b/source/Breakpoint/Breakpoint.cpp
index beb0f6bc5a6e..23d484f0f68a 100644
--- a/source/Breakpoint/Breakpoint.cpp
+++ b/source/Breakpoint/Breakpoint.cpp
@@ -31,7 +31,6 @@
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
-#include "lldb/lldb-private-log.h"
#include "llvm/Support/Casting.h"
using namespace lldb;
@@ -877,25 +876,18 @@ Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_l
{
s->Printf ("no locations (pending).");
}
- else if (num_locations == 1)
+ else if (num_locations == 1 && show_locations == false)
{
- // If there is one location only, we'll just print that location information. But don't do this if
- // show locations is true, then that will be handled below.
- if (show_locations == false)
- {
- GetLocationAtIndex(0)->GetDescription(s, level);
- }
- else
- {
- s->Printf ("%zd locations.", num_locations);
- }
+ // There is only one location, so we'll just print that location information.
+ GetLocationAtIndex(0)->GetDescription(s, level);
}
else
{
- s->Printf ("%zd locations.", num_locations);
+ s->Printf ("%" PRIu64 " locations.", static_cast<uint64_t>(num_locations));
}
s->EOL();
break;
+
case lldb::eDescriptionLevelVerbose:
// Verbose mode does a debug dump of the breakpoint
Dump (s);
@@ -957,6 +949,34 @@ Breakpoint::GetFilterDescription (Stream *s)
m_filter_sp->GetDescription (s);
}
+bool
+Breakpoint::EvaluatePrecondition (StoppointCallbackContext &context)
+{
+ if (!m_precondition_sp)
+ return true;
+
+ return m_precondition_sp->EvaluatePrecondition(context);
+}
+
+bool
+Breakpoint::BreakpointPrecondition::EvaluatePrecondition(StoppointCallbackContext &context)
+{
+ return true;
+}
+
+void
+Breakpoint::BreakpointPrecondition::DescribePrecondition(Stream &stream, lldb::DescriptionLevel level)
+{
+}
+
+Error
+Breakpoint::BreakpointPrecondition::ConfigurePrecondition(Args &options)
+{
+ Error error;
+ error.SetErrorString("Base breakpoint precondition has no options.");
+ return error;
+}
+
void
Breakpoint::SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind)
{
diff --git a/source/Breakpoint/BreakpointLocation.cpp b/source/Breakpoint/BreakpointLocation.cpp
index 85233c9374cb..ef9144778df0 100644
--- a/source/Breakpoint/BreakpointLocation.cpp
+++ b/source/Breakpoint/BreakpointLocation.cpp
@@ -7,15 +7,12 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
// C++ Includes
#include <string>
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/BreakpointID.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
@@ -23,6 +20,8 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Expression/ClangUserExpression.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/Target.h"
@@ -535,6 +534,7 @@ bool
BreakpointLocation::SetBreakpointSite (BreakpointSiteSP& bp_site_sp)
{
m_bp_site_sp = bp_site_sp;
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeLocationsResolved);
return true;
}
@@ -590,7 +590,7 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
s->PutCString ("re-exported target = ");
else
s->PutCString("where = ");
- sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false, true);
+ sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false, true, true);
}
else
{
diff --git a/source/Breakpoint/BreakpointLocationCollection.cpp b/source/Breakpoint/BreakpointLocationCollection.cpp
index 5756ccedfaa4..5b6e746f911d 100644
--- a/source/Breakpoint/BreakpointLocationCollection.cpp
+++ b/source/Breakpoint/BreakpointLocationCollection.cpp
@@ -138,11 +138,17 @@ bool
BreakpointLocationCollection::ShouldStop (StoppointCallbackContext *context)
{
bool shouldStop = false;
- const size_t count = GetSize();
- for (size_t i = 0; i < count; i++)
+ size_t i = 0;
+ size_t prev_size = GetSize();
+ while (i < prev_size)
{
+ // ShouldStop can remove the breakpoint from the list
if (GetByIndex(i)->ShouldStop(context))
shouldStop = true;
+
+ if (prev_size == GetSize())
+ i++;
+ prev_size = GetSize();
}
return shouldStop;
}
diff --git a/source/Breakpoint/BreakpointResolver.cpp b/source/Breakpoint/BreakpointResolver.cpp
index 33b0ff40e35f..f02eadf86a7c 100644
--- a/source/Breakpoint/BreakpointResolver.cpp
+++ b/source/Breakpoint/BreakpointResolver.cpp
@@ -25,7 +25,6 @@
#include "lldb/Target/Target.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb_private;
using namespace lldb;
diff --git a/source/Breakpoint/BreakpointResolverAddress.cpp b/source/Breakpoint/BreakpointResolverAddress.cpp
index d6647130c54c..193bc413af05 100644
--- a/source/Breakpoint/BreakpointResolverAddress.cpp
+++ b/source/Breakpoint/BreakpointResolverAddress.cpp
@@ -13,11 +13,11 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
using namespace lldb;
diff --git a/source/Breakpoint/BreakpointResolverFileLine.cpp b/source/Breakpoint/BreakpointResolverFileLine.cpp
index 950054c3d720..408998ec83ab 100644
--- a/source/Breakpoint/BreakpointResolverFileLine.cpp
+++ b/source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -19,7 +19,6 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
@@ -33,13 +32,15 @@ BreakpointResolverFileLine::BreakpointResolverFileLine
const FileSpec &file_spec,
uint32_t line_no,
bool check_inlines,
- bool skip_prologue
+ bool skip_prologue,
+ bool exact_match
) :
BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver),
m_file_spec (file_spec),
m_line_number (line_no),
m_inlines (check_inlines),
- m_skip_prologue(skip_prologue)
+ m_skip_prologue(skip_prologue),
+ m_exact_match(exact_match)
{
}
@@ -79,7 +80,7 @@ BreakpointResolverFileLine::SearchCallback
if (cu_sp)
{
if (filter.CompUnitPasses(*cu_sp))
- cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list);
+ cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, m_exact_match, eSymbolContextEverything, sc_list);
}
}
StreamString s;
@@ -101,7 +102,7 @@ BreakpointResolverFileLine::GetDepth()
void
BreakpointResolverFileLine::GetDescription (Stream *s)
{
- s->Printf ("file = '%s', line = %u", m_file_spec.GetPath().c_str(), m_line_number);
+ s->Printf ("file = '%s', line = %u, exact_match = %d", m_file_spec.GetPath().c_str(), m_line_number, m_exact_match);
}
void
@@ -117,7 +118,8 @@ BreakpointResolverFileLine::CopyForBreakpoint (Breakpoint &breakpoint)
m_file_spec,
m_line_number,
m_inlines,
- m_skip_prologue));
+ m_skip_prologue,
+ m_exact_match));
return ret_sp;
}
diff --git a/source/Breakpoint/BreakpointResolverFileRegex.cpp b/source/Breakpoint/BreakpointResolverFileRegex.cpp
index c71d9bf5ba8c..e7bce0524c57 100644
--- a/source/Breakpoint/BreakpointResolverFileRegex.cpp
+++ b/source/Breakpoint/BreakpointResolverFileRegex.cpp
@@ -19,7 +19,6 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/Target.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
@@ -30,10 +29,12 @@ using namespace lldb_private;
BreakpointResolverFileRegex::BreakpointResolverFileRegex
(
Breakpoint *bkpt,
- RegularExpression &regex
+ RegularExpression &regex,
+ bool exact_match
) :
BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver),
- m_regex (regex)
+ m_regex (regex),
+ m_exact_match (exact_match)
{
}
@@ -65,9 +66,8 @@ BreakpointResolverFileRegex::SearchCallback
{
SymbolContextList sc_list;
const bool search_inlines = false;
- const bool exact = false;
- cu->ResolveSymbolContext (cu_file_spec, line_matches[i], search_inlines, exact, eSymbolContextEverything, sc_list);
+ cu->ResolveSymbolContext (cu_file_spec, line_matches[i], search_inlines, m_exact_match, eSymbolContextEverything, sc_list);
const bool skip_prologue = true;
BreakpointResolver::SetSCMatchesByLine (filter, sc_list, skip_prologue, m_regex.GetText());
@@ -86,7 +86,7 @@ BreakpointResolverFileRegex::GetDepth()
void
BreakpointResolverFileRegex::GetDescription (Stream *s)
{
- s->Printf ("source regex = \"%s\"", m_regex.GetText());
+ s->Printf ("source regex = \"%s\", exact_match = %d", m_regex.GetText(), m_exact_match);
}
void
@@ -98,7 +98,7 @@ BreakpointResolverFileRegex::Dump (Stream *s) const
lldb::BreakpointResolverSP
BreakpointResolverFileRegex::CopyForBreakpoint (Breakpoint &breakpoint)
{
- lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(&breakpoint, m_regex));
+ lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(&breakpoint, m_regex, m_exact_match));
return ret_sp;
}
diff --git a/source/Breakpoint/BreakpointSite.cpp b/source/Breakpoint/BreakpointSite.cpp
index 469514b03f8a..e9ce812e7732 100644
--- a/source/Breakpoint/BreakpointSite.cpp
+++ b/source/Breakpoint/BreakpointSite.cpp
@@ -11,11 +11,14 @@
// C Includes
// C++ Includes
+#include <inttypes.h>
+
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/BreakpointSiteList.h"
+#include "lldb/Core/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/source/Commands/CommandCompletions.cpp b/source/Commands/CommandCompletions.cpp
index c65dd9d460f4..37696e3bbfdb 100644
--- a/source/Commands/CommandCompletions.cpp
+++ b/source/Commands/CommandCompletions.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
#include <sys/stat.h>
#if defined(__APPLE__) || defined(__linux__)
@@ -25,6 +23,7 @@
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Target/Target.h"
diff --git a/source/Commands/CommandObjectApropos.cpp b/source/Commands/CommandObjectApropos.cpp
index 02dc7269775d..47890b1e83b7 100644
--- a/source/Commands/CommandObjectApropos.cpp
+++ b/source/Commands/CommandObjectApropos.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectApropos.h"
// C Includes
@@ -17,6 +15,7 @@
// Project includes
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/Property.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
diff --git a/source/Commands/CommandObjectArgs.cpp b/source/Commands/CommandObjectArgs.cpp
index b0fe42bc2446..cf32d104911c 100644
--- a/source/Commands/CommandObjectArgs.cpp
+++ b/source/Commands/CommandObjectArgs.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectArgs.h"
// C Includes
@@ -25,8 +23,10 @@
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
diff --git a/source/Commands/CommandObjectBreakpoint.cpp b/source/Commands/CommandObjectBreakpoint.cpp
index 025524b3b9a5..4cbcb70d5fd2 100644
--- a/source/Commands/CommandObjectBreakpoint.cpp
+++ b/source/Commands/CommandObjectBreakpoint.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectBreakpoint.h"
#include "CommandObjectBreakpointCommand.h"
@@ -21,12 +19,14 @@
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionValueBoolean.h"
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Interpreter/OptionValueUInt64.h"
#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Target/StackFrame.h"
@@ -110,9 +110,11 @@ public:
m_catch_bp (false),
m_throw_bp (true),
m_hardware (false),
- m_language (eLanguageTypeUnknown),
+ m_exception_language (eLanguageTypeUnknown),
m_skip_prologue (eLazyBoolCalculate),
- m_one_shot (false)
+ m_one_shot (false),
+ m_all_files (false),
+ m_move_to_nearest_code (eLazyBoolCalculate)
{
}
@@ -135,15 +137,23 @@ public:
}
break;
+ case 'A':
+ m_all_files = true;
+ break;
+
case 'b':
m_func_names.push_back (option_arg);
m_func_name_type_mask |= eFunctionNameTypeBase;
break;
case 'C':
- m_column = StringConvert::ToUInt32 (option_arg, 0);
+ {
+ bool success;
+ m_column = StringConvert::ToUInt32 (option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid column number: %s", option_arg);
break;
-
+ }
case 'c':
m_condition.assign(option_arg);
break;
@@ -162,16 +172,16 @@ public:
case eLanguageTypeC:
case eLanguageTypeC99:
case eLanguageTypeC11:
- m_language = eLanguageTypeC;
+ m_exception_language = eLanguageTypeC;
break;
case eLanguageTypeC_plus_plus:
case eLanguageTypeC_plus_plus_03:
case eLanguageTypeC_plus_plus_11:
case eLanguageTypeC_plus_plus_14:
- m_language = eLanguageTypeC_plus_plus;
+ m_exception_language = eLanguageTypeC_plus_plus;
break;
case eLanguageTypeObjC:
- m_language = eLanguageTypeObjC;
+ m_exception_language = eLanguageTypeObjC;
break;
case eLanguageTypeObjC_plus_plus:
error.SetErrorStringWithFormat ("Set exception breakpoints separately for c++ and objective-c");
@@ -231,8 +241,28 @@ public:
break;
case 'l':
- m_line_num = StringConvert::ToUInt32 (option_arg, 0);
+ {
+ bool success;
+ m_line_num = StringConvert::ToUInt32 (option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("invalid line number: %s.", option_arg);
+ break;
+ }
+
+ case 'm':
+ {
+ bool success;
+ bool value;
+ value = Args::StringToBoolean (option_arg, true, &success);
+ if (value)
+ m_move_to_nearest_code = eLazyBoolYes;
+ else
+ m_move_to_nearest_code = eLazyBoolNo;
+
+ if (!success)
+ error.SetErrorStringWithFormat ("Invalid boolean value for move-to-nearest-code option: '%s'", option_arg);
break;
+ }
case 'M':
m_func_names.push_back (option_arg);
@@ -253,6 +283,11 @@ public:
m_one_shot = true;
break;
+ case 'O':
+ m_exception_extra_args.AppendArgument ("-O");
+ m_exception_extra_args.AppendArgument (option_arg);
+ break;
+
case 'p':
m_source_text_regexp.assign (option_arg);
break;
@@ -334,11 +369,14 @@ public:
m_catch_bp = false;
m_throw_bp = true;
m_hardware = false;
- m_language = eLanguageTypeUnknown;
+ m_exception_language = eLanguageTypeUnknown;
m_skip_prologue = eLazyBoolCalculate;
m_one_shot = false;
m_use_dummy = false;
m_breakpoint_names.clear();
+ m_all_files = false;
+ m_exception_extra_args.Clear();
+ m_move_to_nearest_code = eLazyBoolCalculate;
}
const OptionDefinition*
@@ -372,10 +410,13 @@ public:
bool m_catch_bp;
bool m_throw_bp;
bool m_hardware; // Request to use hardware breakpoints
- lldb::LanguageType m_language;
+ lldb::LanguageType m_exception_language;
LazyBool m_skip_prologue;
bool m_one_shot;
bool m_use_dummy;
+ bool m_all_files;
+ Args m_exception_extra_args;
+ LazyBool m_move_to_nearest_code;
};
@@ -413,7 +454,7 @@ protected:
break_type = eSetTypeFunctionRegexp;
else if (!m_options.m_source_text_regexp.empty())
break_type = eSetTypeSourceRegexp;
- else if (m_options.m_language != eLanguageTypeUnknown)
+ else if (m_options.m_exception_language != eLanguageTypeUnknown)
break_type = eSetTypeException;
Breakpoint *bp = NULL;
@@ -453,7 +494,8 @@ protected:
check_inlines,
m_options.m_skip_prologue,
internal,
- m_options.m_hardware).get();
+ m_options.m_hardware,
+ m_options.m_move_to_nearest_code).get();
}
break;
@@ -505,7 +547,7 @@ protected:
{
const size_t num_files = m_options.m_filenames.GetSize();
- if (num_files == 0)
+ if (num_files == 0 && !m_options.m_all_files)
{
FileSpec file;
if (!GetDefaultFile (target, file, result))
@@ -534,15 +576,27 @@ protected:
&(m_options.m_filenames),
regexp,
internal,
- m_options.m_hardware).get();
+ m_options.m_hardware,
+ m_options.m_move_to_nearest_code).get();
}
break;
case eSetTypeException:
{
- bp = target->CreateExceptionBreakpoint (m_options.m_language,
+ Error precond_error;
+ bp = target->CreateExceptionBreakpoint (m_options.m_exception_language,
m_options.m_catch_bp,
m_options.m_throw_bp,
- m_options.m_hardware).get();
+ internal,
+ &m_options.m_exception_extra_args,
+ &precond_error).get();
+ if (precond_error.Fail())
+ {
+ result.AppendErrorWithFormat("Error setting extra exception arguments: %s",
+ precond_error.AsCString());
+ target->RemoveBreakpointByID(bp->GetID());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
}
break;
default:
@@ -654,6 +708,7 @@ private:
#define LLDB_OPT_FILE ( LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2 )
#define LLDB_OPT_NOT_10 ( LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10 )
#define LLDB_OPT_SKIP_PROLOGUE ( LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3,8) )
+#define LLDB_OPT_MOVE_TO_NEAREST_CODE ( LLDB_OPT_SET_1 | LLDB_OPT_SET_9 )
OptionDefinition
CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
@@ -729,6 +784,9 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
"specified with the -f option. The -f option can be specified more than once. "
"If no source files are specified, uses the current \"default source file\"" },
+ { LLDB_OPT_SET_9, false, "all-files", 'A', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
+ "All files are searched for source pattern matches." },
+
{ LLDB_OPT_SET_10, true, "language-exception", 'E', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLanguage,
"Set the breakpoint on exceptions thrown by the specified language (without options, on throw but not catch.)" },
@@ -738,6 +796,10 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
{ LLDB_OPT_SET_10, false, "on-catch", 'h', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,
"Set the breakpoint on exception catcH." },
+// Don't add this option till it actually does something useful...
+// { LLDB_OPT_SET_10, false, "exception-typename", 'O', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeTypeName,
+// "The breakpoint will only stop if an exception Object of this type is thrown. Can be repeated multiple times to stop for multiple object types" },
+
{ LLDB_OPT_SKIP_PROLOGUE, false, "skip-prologue", 'K', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,
"sKip the prologue if the breakpoint is at the beginning of a function. If not set the target.skip-prologue setting is used." },
@@ -747,6 +809,9 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
{ LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointName,
"Adds this to the list of names for this breakopint."},
+ { LLDB_OPT_MOVE_TO_NEAREST_CODE, false, "move-to-nearest-code", 'm', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,
+ "Move breakpoints to nearest code. If not set the target.move-to-nearest-code setting is used." },
+
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1940,15 +2005,15 @@ public:
{
case 'N':
if (BreakpointID::StringIsBreakpointName(option_value, error) && error.Success())
- m_name.SetValueFromCString(option_value);
+ m_name.SetValueFromString(option_value);
break;
case 'B':
- if (m_breakpoint.SetValueFromCString(option_value).Fail())
+ if (m_breakpoint.SetValueFromString(option_value).Fail())
error.SetErrorStringWithFormat ("unrecognized value \"%s\" for breakpoint", option_value);
break;
case 'D':
- if (m_use_dummy.SetValueFromCString(option_value).Fail())
+ if (m_use_dummy.SetValueFromString(option_value).Fail())
error.SetErrorStringWithFormat ("unrecognized value \"%s\" for use-dummy", option_value);
break;
@@ -2188,7 +2253,6 @@ public:
}
protected:
-protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
diff --git a/source/Commands/CommandObjectBreakpointCommand.cpp b/source/Commands/CommandObjectBreakpointCommand.cpp
index 8f8404b712a5..180ab600a50e 100644
--- a/source/Commands/CommandObjectBreakpointCommand.cpp
+++ b/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
// C++ Includes
diff --git a/source/Commands/CommandObjectBugreport.cpp b/source/Commands/CommandObjectBugreport.cpp
new file mode 100644
index 000000000000..f171d2f6267f
--- /dev/null
+++ b/source/Commands/CommandObjectBugreport.cpp
@@ -0,0 +1,145 @@
+//===-- CommandObjectBugreport.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectBugreport.h"
+
+// C Includes
+#include <cstdio>
+
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionGroupOutputFile.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// "bugreport unwind"
+//-------------------------------------------------------------------------
+
+class CommandObjectBugreportUnwind : public CommandObjectParsed
+{
+public:
+ CommandObjectBugreportUnwind(CommandInterpreter &interpreter) :
+ CommandObjectParsed(interpreter,
+ "bugreport unwind",
+ "Create a bugreport for a bug in the stack unwinding code.",
+ nullptr),
+ m_option_group(interpreter),
+ m_outfile_options()
+ {
+ m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectBugreportUnwind()
+ {
+ }
+
+ Options *
+ GetOptions() override
+ {
+ return &m_option_group;
+ }
+
+protected:
+ bool
+ DoExecute(Args& command, CommandReturnObject &result) override
+ {
+ StringList commands;
+ commands.AppendString("thread backtrace");
+
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ if (thread)
+ {
+ char command_buffer[256];
+
+ uint32_t frame_count = thread->GetStackFrameCount();
+ for (uint32_t i = 0; i < frame_count; ++i)
+ {
+ StackFrameSP frame = thread->GetStackFrameAtIndex(i);
+ lldb::addr_t pc = frame->GetStackID().GetPC();
+
+ snprintf(command_buffer, sizeof(command_buffer), "disassemble --bytes --address 0x%" PRIx64, pc);
+ commands.AppendString(command_buffer);
+
+ snprintf(command_buffer, sizeof(command_buffer), "image show-unwind --address 0x%" PRIx64, pc);
+ commands.AppendString(command_buffer);
+ }
+ }
+
+ const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
+ if (outfile_spec)
+ {
+ char path[PATH_MAX];
+ outfile_spec.GetPath (path, sizeof(path));
+
+ uint32_t open_options = File::eOpenOptionWrite |
+ File::eOpenOptionCanCreate |
+ File::eOpenOptionAppend |
+ File::eOpenOptionCloseOnExec;
+
+ const bool append = m_outfile_options.GetAppend().GetCurrentValue();
+ if (!append)
+ open_options |= File::eOpenOptionTruncate;
+
+ StreamFileSP outfile_stream = std::make_shared<StreamFile>();
+ Error error = outfile_stream->GetFile().Open(path, open_options);
+ if (error.Fail())
+ {
+ result.AppendErrorWithFormat("Failed to open file '%s' for %s: %s\n",
+ path,
+ append ? "append" : "write",
+ error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ result.SetImmediateOutputStream(outfile_stream);
+ }
+
+ CommandInterpreterRunOptions options;
+ options.SetStopOnError(false);
+ options.SetEchoCommands(true);
+ options.SetPrintResults(true);
+ options.SetAddToHistory(false);
+ m_interpreter.HandleCommands(commands, &m_exe_ctx, options, result);
+
+ return result.Succeeded();
+ }
+
+private:
+ OptionGroupOptions m_option_group;
+ OptionGroupOutputFile m_outfile_options;
+};
+
+#pragma mark CommandObjectMultiwordBugreport
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordBugreport
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordBugreport::CommandObjectMultiwordBugreport(CommandInterpreter &interpreter) :
+ CommandObjectMultiword(interpreter,
+ "bugreport",
+ "Set of commands for creating domain specific bugreports.",
+ "bugreport <subcommand> [<subcommand-options>]")
+{
+
+ LoadSubCommand("unwind", CommandObjectSP(new CommandObjectBugreportUnwind(interpreter)));
+}
+
+CommandObjectMultiwordBugreport::~CommandObjectMultiwordBugreport ()
+{
+}
diff --git a/source/Commands/CommandObjectBugreport.h b/source/Commands/CommandObjectBugreport.h
new file mode 100644
index 000000000000..d062e0d79373
--- /dev/null
+++ b/source/Commands/CommandObjectBugreport.h
@@ -0,0 +1,36 @@
+//===-- CommandObjectBugreport.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectBugreport_h_
+#define liblldb_CommandObjectBugreport_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordBugreport
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordBugreport : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordBugreport(CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordBugreport();
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectBugreport_h_
diff --git a/source/Commands/CommandObjectCommands.cpp b/source/Commands/CommandObjectCommands.cpp
index f98eac055f24..5fd99cfdabf4 100644
--- a/source/Commands/CommandObjectCommands.cpp
+++ b/source/Commands/CommandObjectCommands.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectCommands.h"
// C Includes
@@ -29,7 +27,6 @@
#include "lldb/Interpreter/OptionValueUInt64.h"
#include "lldb/Interpreter/Options.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
-#include "lldb/Interpreter/ScriptInterpreterPython.h"
using namespace lldb;
using namespace lldb_private;
@@ -85,7 +82,7 @@ protected:
switch (short_option)
{
case 'c':
- error = m_count.SetValueFromCString(option_arg,eVarSetOperationAssign);
+ error = m_count.SetValueFromString(option_arg,eVarSetOperationAssign);
break;
case 's':
if (option_arg && strcmp("end", option_arg) == 0)
@@ -94,10 +91,10 @@ protected:
m_start_idx.SetOptionWasSet();
}
else
- error = m_start_idx.SetValueFromCString(option_arg,eVarSetOperationAssign);
+ error = m_start_idx.SetValueFromString(option_arg,eVarSetOperationAssign);
break;
case 'e':
- error = m_stop_idx.SetValueFromCString(option_arg,eVarSetOperationAssign);
+ error = m_stop_idx.SetValueFromString(option_arg,eVarSetOperationAssign);
break;
case 'C':
m_clear.SetCurrentValue(true);
@@ -326,15 +323,15 @@ protected:
switch (short_option)
{
case 'e':
- error = m_stop_on_error.SetValueFromCString(option_arg);
+ error = m_stop_on_error.SetValueFromString(option_arg);
break;
case 'c':
- error = m_stop_on_continue.SetValueFromCString(option_arg);
+ error = m_stop_on_continue.SetValueFromString(option_arg);
break;
case 's':
- error = m_silent_run.SetValueFromCString(option_arg);
+ error = m_silent_run.SetValueFromString(option_arg);
break;
default:
@@ -1430,6 +1427,130 @@ protected:
};
+class CommandObjectScriptingObject : public CommandObjectRaw
+{
+private:
+ StructuredData::GenericSP m_cmd_obj_sp;
+ ScriptedCommandSynchronicity m_synchro;
+ bool m_fetched_help_short:1;
+ bool m_fetched_help_long:1;
+
+public:
+
+ CommandObjectScriptingObject (CommandInterpreter &interpreter,
+ std::string name,
+ StructuredData::GenericSP cmd_obj_sp,
+ ScriptedCommandSynchronicity synch) :
+ CommandObjectRaw (interpreter,
+ name.c_str(),
+ NULL,
+ NULL),
+ m_cmd_obj_sp(cmd_obj_sp),
+ m_synchro(synch),
+ m_fetched_help_short(false),
+ m_fetched_help_long(false)
+ {
+ StreamString stream;
+ stream.Printf("For more information run 'help %s'",name.c_str());
+ SetHelp(stream.GetData());
+ if (ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter())
+ GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
+ }
+
+ virtual
+ ~CommandObjectScriptingObject ()
+ {
+ }
+
+ virtual bool
+ IsRemovable () const
+ {
+ return true;
+ }
+
+ StructuredData::GenericSP
+ GetImplementingObject ()
+ {
+ return m_cmd_obj_sp;
+ }
+
+ ScriptedCommandSynchronicity
+ GetSynchronicity ()
+ {
+ return m_synchro;
+ }
+
+ virtual const char *
+ GetHelp ()
+ {
+ if (!m_fetched_help_short)
+ {
+ ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
+ if (scripter)
+ {
+ std::string docstring;
+ m_fetched_help_short = scripter->GetShortHelpForCommandObject(m_cmd_obj_sp,docstring);
+ if (!docstring.empty())
+ SetHelp(docstring);
+ }
+ }
+ return CommandObjectRaw::GetHelp();
+ }
+
+ virtual const char *
+ GetHelpLong ()
+ {
+ if (!m_fetched_help_long)
+ {
+ ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
+ if (scripter)
+ {
+ std::string docstring;
+ m_fetched_help_long = scripter->GetLongHelpForCommandObject(m_cmd_obj_sp,docstring);
+ if (!docstring.empty())
+ SetHelpLong(docstring);
+ }
+ }
+ return CommandObjectRaw::GetHelpLong();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *raw_command_line, CommandReturnObject &result)
+ {
+ ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
+
+ Error error;
+
+ result.SetStatus(eReturnStatusInvalid);
+
+ if (!scripter || scripter->RunScriptBasedCommand(m_cmd_obj_sp,
+ raw_command_line,
+ m_synchro,
+ result,
+ error,
+ m_exe_ctx) == false)
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+ else
+ {
+ // Don't change the status if the command already set it...
+ if (result.GetStatus() == eReturnStatusInvalid)
+ {
+ if (result.GetOutputData() == NULL || result.GetOutputData()[0] == '\0')
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ else
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
//-------------------------------------------------------------------------
// CommandObjectCommandsScriptImport
//-------------------------------------------------------------------------
@@ -1449,7 +1570,7 @@ public:
// Define the first (and only) variant of this arg.
cmd_arg.arg_type = eArgTypeFilename;
- cmd_arg.arg_repetition = eArgRepeatPlain;
+ cmd_arg.arg_repetition = eArgRepeatPlus;
// There is only one variant this argument could be; put it into the argument entry.
arg1.push_back (cmd_arg);
@@ -1549,7 +1670,6 @@ protected:
bool
DoExecute (Args& command, CommandReturnObject &result)
{
-
if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython)
{
result.AppendError ("only scripting language supported for module importing is currently Python");
@@ -1558,36 +1678,40 @@ protected:
}
size_t argc = command.GetArgumentCount();
-
- if (argc != 1)
+ if (0 == argc)
{
- result.AppendError ("'command script import' requires one argument");
+ result.AppendError("command script import needs one or more arguments");
result.SetStatus (eReturnStatusFailed);
return false;
}
- std::string path = command.GetArgumentAtIndex(0);
- Error error;
-
- const bool init_session = true;
- // FIXME: this is necessary because CommandObject::CheckRequirements() assumes that
- // commands won't ever be recursively invoked, but it's actually possible to craft
- // a Python script that does other "command script imports" in __lldb_init_module
- // the real fix is to have recursive commands possible with a CommandInvocation object
- // separate from the CommandObject itself, so that recursive command invocations
- // won't stomp on each other (wrt to execution contents, options, and more)
- m_exe_ctx.Clear();
- if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(),
- m_options.m_allow_reload,
- init_session,
- error))
- {
- result.SetStatus (eReturnStatusSuccessFinishNoResult);
- }
- else
+ for (size_t i = 0;
+ i < argc;
+ i++)
{
- result.AppendErrorWithFormat("module importing failed: %s", error.AsCString());
- result.SetStatus (eReturnStatusFailed);
+ std::string path = command.GetArgumentAtIndex(i);
+ Error error;
+
+ const bool init_session = true;
+ // FIXME: this is necessary because CommandObject::CheckRequirements() assumes that
+ // commands won't ever be recursively invoked, but it's actually possible to craft
+ // a Python script that does other "command script imports" in __lldb_init_module
+ // the real fix is to have recursive commands possible with a CommandInvocation object
+ // separate from the CommandObject itself, so that recursive command invocations
+ // won't stomp on each other (wrt to execution contents, options, and more)
+ m_exe_ctx.Clear();
+ if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(),
+ m_options.m_allow_reload,
+ init_session,
+ error))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("module importing failed: %s", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
}
return result.Succeeded();
@@ -1652,7 +1776,11 @@ protected:
public:
CommandOptions (CommandInterpreter &interpreter) :
- Options (interpreter)
+ Options (interpreter),
+ m_class_name(),
+ m_funct_name(),
+ m_short_help(),
+ m_synchronicity(eScriptedCommandSynchronicitySynchronous)
{
}
@@ -1671,6 +1799,10 @@ protected:
if (option_arg)
m_funct_name.assign(option_arg);
break;
+ case 'c':
+ if (option_arg)
+ m_class_name.assign(option_arg);
+ break;
case 'h':
if (option_arg)
m_short_help.assign(option_arg);
@@ -1691,6 +1823,7 @@ protected:
void
OptionParsingStarting ()
{
+ m_class_name.clear();
m_funct_name.clear();
m_short_help.clear();
m_synchronicity = eScriptedCommandSynchronicitySynchronous;
@@ -1708,6 +1841,7 @@ protected:
// Instance variables to hold the values for command options.
+ std::string m_class_name;
std::string m_funct_name;
std::string m_short_help;
ScriptedCommandSynchronicity m_synchronicity;
@@ -1812,20 +1946,55 @@ protected:
m_short_help.assign(m_options.m_short_help);
m_synchronicity = m_options.m_synchronicity;
- if (m_options.m_funct_name.empty())
+ if (m_options.m_class_name.empty())
{
- m_interpreter.GetPythonCommandsFromIOHandler (" ", // Prompt
- *this, // IOHandlerDelegate
- true, // Run IOHandler in async mode
- NULL); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions
+ if (m_options.m_funct_name.empty())
+ {
+ m_interpreter.GetPythonCommandsFromIOHandler (" ", // Prompt
+ *this, // IOHandlerDelegate
+ true, // Run IOHandler in async mode
+ NULL); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions
+ }
+ else
+ {
+ CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter,
+ m_cmd_name,
+ m_options.m_funct_name,
+ m_options.m_short_help,
+ m_synchronicity));
+ if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError("cannot add command");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
}
else
{
- CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter,
- m_cmd_name,
- m_options.m_funct_name,
- m_options.m_short_help,
- m_synchronicity));
+ ScriptInterpreter *interpreter = GetCommandInterpreter().GetScriptInterpreter();
+ if (!interpreter)
+ {
+ result.AppendError("cannot find ScriptInterpreter");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ auto cmd_obj_sp = interpreter->CreateScriptCommandObject(m_options.m_class_name.c_str());
+ if (!cmd_obj_sp)
+ {
+ result.AppendError("cannot create helper object");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ CommandObjectSP new_cmd(new CommandObjectScriptingObject(m_interpreter,
+ m_cmd_name,
+ cmd_obj_sp,
+ m_synchronicity));
if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true))
{
result.SetStatus (eReturnStatusSuccessFinishNoResult);
@@ -1859,8 +2028,9 @@ OptionDefinition
CommandObjectCommandsScriptAdd::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name."},
+ { LLDB_OPT_SET_2, false, "class", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonClass, "Name of the Python class to bind to this command name."},
{ LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeHelpText, "The help text to display for this command."},
- { LLDB_OPT_SET_1, false, "synchronicity", 's', OptionParser::eRequiredArgument, NULL, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."},
+ { LLDB_OPT_SET_ALL, false, "synchronicity", 's', OptionParser::eRequiredArgument, NULL, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."},
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
diff --git a/source/Commands/CommandObjectDisassemble.cpp b/source/Commands/CommandObjectDisassemble.cpp
index 2ba47be1ecf0..1e575fe963f3 100644
--- a/source/Commands/CommandObjectDisassemble.cpp
+++ b/source/Commands/CommandObjectDisassemble.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectDisassemble.h"
// C Includes
diff --git a/source/Commands/CommandObjectExpression.cpp b/source/Commands/CommandObjectExpression.cpp
index e87399f97baa..f4bb8fbac11e 100644
--- a/source/Commands/CommandObjectExpression.cpp
+++ b/source/Commands/CommandObjectExpression.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectExpression.h"
// C Includes
@@ -196,7 +194,7 @@ CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interprete
"expression",
"Evaluate a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope.",
NULL,
- eFlagProcessMustBePaused | eFlagTryTargetAPILock),
+ eCommandProcessMustBePaused | eCommandTryTargetAPILock),
IOHandlerDelegate (IOHandlerDelegate::Completion::Expression),
m_option_group (interpreter),
m_format_options (eFormatDefault),
@@ -487,7 +485,7 @@ CommandObjectExpression::DoExecute
if (end_options)
{
- Args args (command, end_options - command);
+ Args args (llvm::StringRef(command, end_options - command));
if (!ParseOptions (args, result))
return false;
diff --git a/source/Commands/CommandObjectFrame.cpp b/source/Commands/CommandObjectFrame.cpp
index 4458a692a189..d8b65e3b551a 100644
--- a/source/Commands/CommandObjectFrame.cpp
+++ b/source/Commands/CommandObjectFrame.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectFrame.h"
// C Includes
@@ -65,10 +63,10 @@ public:
"frame info",
"List information about the currently selected frame in the current thread.",
"frame info",
- eFlagRequiresFrame |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused )
+ eCommandRequiresFrame |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused )
{
}
@@ -156,10 +154,10 @@ public:
"frame select",
"Select a frame by index from within the current thread and make it the current frame.",
NULL,
- eFlagRequiresThread |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresThread |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_options (interpreter)
{
CommandArgumentEntry arg;
@@ -192,7 +190,7 @@ protected:
bool
DoExecute (Args& command, CommandReturnObject &result)
{
- // No need to check "thread" for validity as eFlagRequiresThread ensures it is valid
+ // No need to check "thread" for validity as eCommandRequiresThread ensures it is valid
Thread *thread = m_exe_ctx.GetThreadPtr();
uint32_t frame_idx = UINT32_MAX;
@@ -314,11 +312,11 @@ public:
"Children of aggregate variables can be specified such as "
"'var->child.x'.",
NULL,
- eFlagRequiresFrame |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused |
- eFlagRequiresProcess),
+ eCommandRequiresFrame |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused |
+ eCommandRequiresProcess),
m_option_group (interpreter),
m_option_variable(true), // Include the frame specific options by passing "true"
m_option_format (eFormatDefault),
@@ -385,7 +383,7 @@ protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- // No need to check "frame" for validity as eFlagRequiresFrame ensures it is valid
+ // No need to check "frame" for validity as eCommandRequiresFrame ensures it is valid
StackFrame *frame = m_exe_ctx.GetFramePtr();
Stream &s = result.GetOutputStream();
@@ -522,30 +520,31 @@ protected:
{
var_sp = variable_list->GetVariableAtIndex(i);
bool dump_variable = true;
+ std::string scope_string;
switch (var_sp->GetScope())
{
case eValueTypeVariableGlobal:
dump_variable = m_option_variable.show_globals;
if (dump_variable && m_option_variable.show_scope)
- s.PutCString("GLOBAL: ");
+ scope_string = "GLOBAL: ";
break;
case eValueTypeVariableStatic:
dump_variable = m_option_variable.show_globals;
if (dump_variable && m_option_variable.show_scope)
- s.PutCString("STATIC: ");
+ scope_string = "STATIC: ";
break;
case eValueTypeVariableArgument:
dump_variable = m_option_variable.show_args;
if (dump_variable && m_option_variable.show_scope)
- s.PutCString(" ARG: ");
+ scope_string = " ARG: ";
break;
case eValueTypeVariableLocal:
dump_variable = m_option_variable.show_locals;
if (dump_variable && m_option_variable.show_scope)
- s.PutCString(" LOCAL: ");
+ scope_string = " LOCAL: ";
break;
default:
@@ -555,7 +554,7 @@ protected:
if (dump_variable)
{
// Use the variable object code to make sure we are
- // using the same APIs as the the public API will be
+ // using the same APIs as the public API will be
// using...
valobj_sp = frame->GetValueObjectForFrameVariable (var_sp,
m_varobj_options.use_dynamic);
@@ -568,6 +567,13 @@ protected:
// that are not in scope to avoid extra unneeded output
if (valobj_sp->IsInScope ())
{
+ if (false == valobj_sp->GetTargetSP()->GetDisplayRuntimeSupportValues() &&
+ true == valobj_sp->IsRuntimeSupportValue())
+ continue;
+
+ if (!scope_string.empty())
+ s.PutCString(scope_string.c_str());
+
if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile())
{
var_sp->GetDeclaration ().DumpStopContext (&s, false);
diff --git a/source/Commands/CommandObjectGUI.cpp b/source/Commands/CommandObjectGUI.cpp
index 359d6d2892d0..0991c7e84874 100644
--- a/source/Commands/CommandObjectGUI.cpp
+++ b/source/Commands/CommandObjectGUI.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectGUI.h"
// C Includes
diff --git a/source/Commands/CommandObjectHelp.cpp b/source/Commands/CommandObjectHelp.cpp
index b02515e2d1e8..18dc44a32b5a 100644
--- a/source/Commands/CommandObjectHelp.cpp
+++ b/source/Commands/CommandObjectHelp.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectHelp.h"
// C Includes
diff --git a/source/Commands/CommandObjectLanguage.cpp b/source/Commands/CommandObjectLanguage.cpp
new file mode 100644
index 000000000000..9d4b85630a1f
--- /dev/null
+++ b/source/Commands/CommandObjectLanguage.cpp
@@ -0,0 +1,44 @@
+//===-- CommandObjectLanguage.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectLanguage.h"
+
+#include "lldb/Host/Host.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+#include "lldb/Target/LanguageRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectLanguage::CommandObjectLanguage (CommandInterpreter &interpreter) :
+CommandObjectMultiword (interpreter,
+ "language",
+ "A set of commands for managing language-specific functionality.'.",
+ "language <language-name> <subcommand> [<subcommand-options>]"
+ )
+{
+ //Let the LanguageRuntime populates this command with subcommands
+ LanguageRuntime::InitializeCommands(this);
+}
+
+void
+CommandObjectLanguage::GenerateHelpText (Stream &output_stream) {
+ CommandObjectMultiword::GenerateHelpText(output_stream);
+
+ output_stream << "\nlanguage name can be one of the following:\n";
+
+ LanguageRuntime::PrintAllLanguages(output_stream, " ", "\n");
+}
+
+CommandObjectLanguage::~CommandObjectLanguage ()
+{
+}
diff --git a/source/Commands/CommandObjectLanguage.h b/source/Commands/CommandObjectLanguage.h
new file mode 100644
index 000000000000..751fe1440a8b
--- /dev/null
+++ b/source/Commands/CommandObjectLanguage.h
@@ -0,0 +1,41 @@
+//===-- CommandObjectLanguage.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectLanguage_h_
+#define liblldb_CommandObjectLanguage_h_
+
+// C Includes
+// C++ Includes
+
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-types.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+ class CommandObjectLanguage : public CommandObjectMultiword
+ {
+ public:
+ CommandObjectLanguage (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectLanguage ();
+
+ virtual void
+ GenerateHelpText (Stream &output_stream);
+
+ protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result);
+ };
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectLanguage_h_
diff --git a/source/Commands/CommandObjectLog.cpp b/source/Commands/CommandObjectLog.cpp
index aa09f53c792b..e68eaf17bb9f 100644
--- a/source/Commands/CommandObjectLog.cpp
+++ b/source/Commands/CommandObjectLog.cpp
@@ -7,16 +7,12 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectLog.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
-
#include "lldb/Interpreter/Args.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Host/FileSpec.h"
@@ -148,6 +144,7 @@ public:
case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break;
case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break;
case 'S': log_options |= LLDB_LOG_OPTION_BACKTRACE; break;
+ case 'a': log_options |= LLDB_LOG_OPTION_APPEND; break;
default:
error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
break;
@@ -225,6 +222,7 @@ CommandObjectLogEnable::CommandOptions::g_option_table[] =
{ LLDB_OPT_SET_1, false, "pid-tid", 'p', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Prepend all log lines with the process and thread ID that generates the log line." },
{ LLDB_OPT_SET_1, false, "thread-name",'n', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Prepend all log lines with the thread name for the thread that generates the log line." },
{ LLDB_OPT_SET_1, false, "stack", 'S', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Append a stack backtrace to each log line." },
+{ LLDB_OPT_SET_1, false, "append", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Append to the log file instead of overwriting." },
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
diff --git a/source/Commands/CommandObjectMemory.cpp b/source/Commands/CommandObjectMemory.cpp
index dac6dd81651b..d589800299a3 100644
--- a/source/Commands/CommandObjectMemory.cpp
+++ b/source/Commands/CommandObjectMemory.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectMemory.h"
// C Includes
@@ -16,6 +14,7 @@
// C++ Includes
// Other libraries and framework includes
+#include "clang/AST/Decl.h"
// Project includes
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
@@ -24,6 +23,7 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/DataFormatters/ValueObjectPrinter.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -95,7 +95,7 @@ public:
switch (short_option)
{
case 'l':
- error = m_num_per_line.SetValueFromCString (option_arg);
+ error = m_num_per_line.SetValueFromString (option_arg);
if (m_num_per_line.GetCurrentValue() == 0)
error.SetErrorStringWithFormat("invalid value for --num-per-line option '%s'", option_arg);
break;
@@ -105,7 +105,7 @@ public:
break;
case 't':
- error = m_view_as_type.SetValueFromCString (option_arg);
+ error = m_view_as_type.SetValueFromString (option_arg);
break;
case 'r':
@@ -313,7 +313,7 @@ public:
"memory read",
"Read from the memory of the process being debugged.",
NULL,
- eFlagRequiresTarget | eFlagProcessMustBePaused),
+ eCommandRequiresTarget | eCommandProcessMustBePaused),
m_option_group (interpreter),
m_format_options (eFormatBytesWithASCII, 1, 8),
m_memory_options (),
@@ -386,7 +386,7 @@ protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- // No need to check "target" for validity as eFlagRequiresTarget ensures it is valid
+ // No need to check "target" for validity as eCommandRequiresTarget ensures it is valid
Target *target = m_exe_ctx.GetTargetPtr();
const size_t argc = command.GetArgumentCount();
@@ -532,7 +532,7 @@ protected:
clang::TypeDecl *tdecl = target->GetPersistentVariables().GetPersistentType(ConstString(lookup_type_name));
if (tdecl)
{
- clang_ast_type.SetClangType(&tdecl->getASTContext(),(lldb::clang_type_t)tdecl->getTypeForDecl());
+ clang_ast_type.SetClangType(&tdecl->getASTContext(),(const lldb::clang_type_t)tdecl->getTypeForDecl());
}
}
@@ -742,6 +742,7 @@ protected:
auto data_addr = addr;
auto count = item_count;
item_count = 0;
+ bool break_on_no_NULL = false;
while (item_count < count)
{
std::string buffer;
@@ -754,17 +755,24 @@ protected:
result.SetStatus(eReturnStatusFailed);
return false;
}
+
if (item_byte_size == read)
{
result.AppendWarningWithFormat("unable to find a NULL terminated string at 0x%" PRIx64 ".Consider increasing the maximum read length.\n", data_addr);
- break;
+ --read;
+ break_on_no_NULL = true;
}
- read+=1; // account for final NULL byte
+ else
+ ++read; // account for final NULL byte
+
memcpy(data_ptr, &buffer[0], read);
data_ptr += read;
data_addr += read;
bytes_read += read;
item_count++; // if we break early we know we only read item_count strings
+
+ if (break_on_no_NULL)
+ break;
}
data_sp.reset(new DataBufferHeap(data_sp->GetBytes(),bytes_read+1));
}
@@ -981,20 +989,20 @@ public:
switch (short_option)
{
case 'e':
- m_expr.SetValueFromCString(option_arg);
+ m_expr.SetValueFromString(option_arg);
break;
case 's':
- m_string.SetValueFromCString(option_arg);
+ m_string.SetValueFromString(option_arg);
break;
case 'c':
- if (m_count.SetValueFromCString(option_arg).Fail())
+ if (m_count.SetValueFromString(option_arg).Fail())
error.SetErrorString("unrecognized value for count");
break;
case 'o':
- if (m_offset.SetValueFromCString(option_arg).Fail())
+ if (m_offset.SetValueFromString(option_arg).Fail())
error.SetErrorString("unrecognized value for dump-offset");
break;
@@ -1024,7 +1032,7 @@ public:
"memory find",
"Find a value in the memory of the process being debugged.",
NULL,
- eFlagRequiresProcess | eFlagProcessMustBeLaunched),
+ eCommandRequiresProcess | eCommandProcessMustBeLaunched),
m_option_group (interpreter),
m_memory_options ()
{
@@ -1070,7 +1078,7 @@ protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
+ // No need to check "process" for validity as eCommandRequiresProcess ensures it is valid
Process *process = m_exe_ctx.GetProcessPtr();
const size_t argc = command.GetArgumentCount();
@@ -1325,7 +1333,7 @@ public:
"memory write",
"Write to the memory of the process being debugged.",
NULL,
- eFlagRequiresProcess | eFlagProcessMustBeLaunched),
+ eCommandRequiresProcess | eCommandProcessMustBeLaunched),
m_option_group (interpreter),
m_format_options (eFormatBytes, 1, UINT64_MAX),
m_memory_options ()
@@ -1402,7 +1410,7 @@ protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
+ // No need to check "process" for validity as eCommandRequiresProcess ensures it is valid
Process *process = m_exe_ctx.GetProcessPtr();
const size_t argc = command.GetArgumentCount();
@@ -1692,7 +1700,7 @@ public:
"memory history",
"Prints out the recorded stack traces for allocation/deallocation of a memory address.",
NULL,
- eFlagRequiresTarget | eFlagRequiresProcess | eFlagProcessMustBePaused | eFlagProcessMustBeLaunched)
+ eCommandRequiresTarget | eCommandRequiresProcess | eCommandProcessMustBePaused | eCommandProcessMustBeLaunched)
{
CommandArgumentEntry arg1;
CommandArgumentData addr_arg;
diff --git a/source/Commands/CommandObjectMultiword.cpp b/source/Commands/CommandObjectMultiword.cpp
index 69b178da46ba..2f0e2a78a0cc 100644
--- a/source/Commands/CommandObjectMultiword.cpp
+++ b/source/Commands/CommandObjectMultiword.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/CommandObjectMultiword.h"
// C Includes
// C++ Includes
@@ -153,7 +151,7 @@ CommandObjectMultiword::Execute(const char *args_string, CommandReturnObject &re
error_msg.append (GetCommandName());
error_msg.append (" ");
error_msg.append (sub_command);
- error_msg.append ("'");
+ error_msg.append ("'.");
if (num_subcmd_matches > 0)
{
@@ -251,23 +249,27 @@ CommandObjectMultiword::HandleCompletion
&temp_matches);
if (cmd_obj != NULL)
{
- matches.DeleteStringAtIndex (0);
- input.Shift();
- cursor_char_position = 0;
- input.AppendArgument ("");
- return cmd_obj->HandleCompletion (input,
- cursor_index,
- cursor_char_position,
- match_start_point,
- max_return_elements,
- word_complete,
- matches);
+ if (input.GetArgumentCount() == 1)
+ {
+ word_complete = true;
+ }
+ else
+ {
+ matches.DeleteStringAtIndex (0);
+ input.Shift();
+ cursor_char_position = 0;
+ input.AppendArgument ("");
+ return cmd_obj->HandleCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
}
- else
- return matches.GetSize();
}
- else
- return matches.GetSize();
+ return matches.GetSize();
}
else
{
diff --git a/source/Commands/CommandObjectPlatform.cpp b/source/Commands/CommandObjectPlatform.cpp
index 959c5cd1d0d7..866587fb4ebc 100644
--- a/source/Commands/CommandObjectPlatform.cpp
+++ b/source/Commands/CommandObjectPlatform.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectPlatform.h"
// C Includes
@@ -558,7 +556,7 @@ protected:
if (platform_sp)
{
if (m_option_working_dir.GetOptionValue().OptionWasSet())
- platform_sp->SetWorkingDirectory (ConstString(m_option_working_dir.GetOptionValue().GetCurrentValue().GetPath().c_str()));
+ platform_sp->SetWorkingDirectory(m_option_working_dir.GetOptionValue().GetCurrentValue());
}
else
{
@@ -572,10 +570,7 @@ protected:
GetOptions ()
{
if (m_options.DidFinalize() == false)
- {
- m_options.Append(new OptionPermissions());
m_options.Finalize();
- }
return &m_options;
}
protected:
@@ -621,7 +616,7 @@ public:
mode = options_permissions->m_permissions;
else
mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX | lldb::eFilePermissionsWorldRX;
- Error error = platform_sp->MakeDirectory(cmd_line.c_str(), mode);
+ Error error = platform_sp->MakeDirectory(FileSpec{cmd_line, false}, mode);
if (error.Success())
{
result.SetStatus (eReturnStatusSuccessFinishResult);
@@ -1201,7 +1196,7 @@ public:
}
else
{
- result.AppendMessageWithFormat("Eroor getting file size of %s (remote)\n", remote_file_path.c_str());
+ result.AppendMessageWithFormat("Error getting file size of %s (remote)\n", remote_file_path.c_str());
result.SetStatus (eReturnStatusFailed);
}
}
@@ -1241,8 +1236,8 @@ public:
const char* dst = args.GetArgumentAtIndex(1);
FileSpec src_fs(src, true);
- FileSpec dst_fs(dst, false);
-
+ FileSpec dst_fs(dst ? dst : src_fs.GetFilename().GetCString(), false);
+
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
if (platform_sp)
{
@@ -1277,7 +1272,7 @@ public:
"platform process launch",
"Launch a new process on a remote platform.",
"platform process launch program",
- eFlagRequiresTarget | eFlagTryTargetAPILock),
+ eCommandRequiresTarget | eCommandTryTargetAPILock),
m_options (interpreter)
{
}
@@ -1975,7 +1970,7 @@ CommandObjectPlatformProcessAttach::CommandOptions::g_option_table[] =
{ LLDB_OPT_SET_ALL, false, "plugin", 'P' , OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
{ LLDB_OPT_SET_1, false, "pid", 'p' , OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePid, "The process ID of an existing process to attach to."},
{ LLDB_OPT_SET_2, false, "name", 'n' , OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName, "The name of the process to attach to."},
- { LLDB_OPT_SET_2, false, "waitfor", 'w' , OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Wait for the the process with <process-name> to launch."},
+ { LLDB_OPT_SET_2, false, "waitfor", 'w' , OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Wait for the process with <process-name> to launch."},
{ 0, false, NULL , 0 , 0 , NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -2085,7 +2080,7 @@ public:
CommandObjectPlatformShell (CommandInterpreter &interpreter) :
CommandObjectRaw (interpreter,
"platform shell",
- "Run a shell command on a the selected platform.",
+ "Run a shell command on the selected platform.",
"platform shell <shell-command>",
0),
m_options(interpreter)
@@ -2142,7 +2137,7 @@ public:
if (end_options)
{
- Args args (raw_command_line, end_options - raw_command_line);
+ Args args (llvm::StringRef(raw_command_line, end_options - raw_command_line));
if (!ParseOptions (args, result))
return false;
}
@@ -2155,7 +2150,7 @@ public:
Error error;
if (platform_sp)
{
- const char *working_dir = NULL;
+ FileSpec working_dir{};
std::string output;
int status = -1;
int signo = -1;
diff --git a/source/Commands/CommandObjectPlugin.cpp b/source/Commands/CommandObjectPlugin.cpp
index 658c077bc3ea..63fa4a82cf91 100644
--- a/source/Commands/CommandObjectPlugin.cpp
+++ b/source/Commands/CommandObjectPlugin.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectPlugin.h"
#include "lldb/Host/Host.h"
diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp
index d47311e5cb5f..4414bdf2a2c8 100644
--- a/source/Commands/CommandObjectProcess.cpp
+++ b/source/Commands/CommandObjectProcess.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectProcess.h"
// C Includes
@@ -32,6 +30,7 @@
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Target/UnixSignals.h"
using namespace lldb;
using namespace lldb_private;
@@ -92,7 +91,7 @@ protected:
}
else
{
- Error destroy_error (process->Destroy());
+ Error destroy_error (process->Destroy(false));
if (destroy_error.Success())
{
result.SetStatus (eReturnStatusSuccessFinishResult);
@@ -124,7 +123,7 @@ public:
"process launch",
"Launch the executable in the debugger.",
NULL,
- eFlagRequiresTarget,
+ eCommandRequiresTarget,
"restart"),
m_options (interpreter)
{
@@ -249,9 +248,7 @@ protected:
if (launch_args.GetArgumentCount() == 0)
{
- Args target_setting_args;
- if (target->GetRunArguments(target_setting_args))
- m_options.launch_info.GetArguments().AppendArguments (target_setting_args);
+ m_options.launch_info.GetArguments().AppendArguments (target->GetProcessLaunchInfo().GetArguments());
}
else
{
@@ -265,13 +262,18 @@ protected:
if (error.Success())
{
- const char *archname = exe_module_sp->GetArchitecture().GetArchitectureName();
ProcessSP process_sp (target->GetProcessSP());
if (process_sp)
{
+ // There is a race condition where this thread will return up the call stack to the main command
+ // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
+ // a chance to call PushProcessIOHandler().
+ process_sp->SyncIOHandler (0, 2000);
+
const char *data = stream.GetData();
if (data && strlen(data) > 0)
result.AppendMessage(stream.GetData());
+ const char *archname = exe_module_sp->GetArchitecture().GetArchitectureName();
result.AppendMessageWithFormat ("Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(), exe_module_sp->GetFileSpec().GetPath().c_str(), archname);
result.SetStatus (eReturnStatusSuccessFinishResult);
result.SetDidChangeProcessState (true);
@@ -529,8 +531,6 @@ protected:
ModuleSP old_exec_module_sp = target->GetExecutableModule();
ArchSpec old_arch_spec = target->GetArchitecture();
- ProcessSP process_sp;
- Error error;
if (command.GetArgumentCount())
{
result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
@@ -539,70 +539,21 @@ protected:
}
m_interpreter.UpdateExecutionContext(nullptr);
- ListenerSP listener_sp (new Listener("lldb.CommandObjectProcessAttach.DoExecute.attach.hijack"));
- m_options.attach_info.SetHijackListener(listener_sp);
-
- // If no process info was specified, then use the target executable
- // name as the process to attach to by default
- if (!m_options.attach_info.ProcessInfoSpecified ())
- {
- if (old_exec_module_sp)
- m_options.attach_info.GetExecutableFile().GetFilename() = old_exec_module_sp->GetPlatformFileSpec().GetFilename();
-
- if (!m_options.attach_info.ProcessInfoSpecified ())
- {
- error.SetErrorString ("no process specified, create a target with a file, or specify the --pid or --name command option");
- }
- }
-
+ StreamString stream;
+ const auto error = target->Attach(m_options.attach_info, &stream);
if (error.Success())
{
- if (state != eStateConnected && platform_sp != nullptr && platform_sp->CanDebugProcess())
- {
- target->SetPlatform(platform_sp);
- process = platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), target, error).get();
- }
- else
- {
- if (state != eStateConnected)
- {
- const char *plugin_name = m_options.attach_info.GetProcessPluginName();
- process = target->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name, nullptr).get();
- if (process == nullptr)
- error.SetErrorStringWithFormat("failed to create process using plugin %s", plugin_name);
- }
- if (process)
- {
- process->HijackProcessEvents(listener_sp.get());
- error = process->Attach(m_options.attach_info);
- }
- }
- }
-
- if (error.Success() && process != nullptr)
- {
- result.SetStatus (eReturnStatusSuccessContinuingNoResult);
- StreamString stream;
- StateType state = process->WaitForProcessToStop (nullptr, nullptr, false, listener_sp.get(), &stream);
-
- process->RestoreProcessEvents();
- result.SetDidChangeProcessState (true);
-
- if (stream.GetData())
- result.AppendMessage(stream.GetData());
-
- if (state == eStateStopped)
+ ProcessSP process_sp (target->GetProcessSP());
+ if (process_sp)
{
+ if (stream.GetData())
+ result.AppendMessage(stream.GetData());
result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ result.SetDidChangeProcessState (true);
}
else
{
- const char *exit_desc = process->GetExitDescription();
- if (exit_desc)
- result.AppendErrorWithFormat ("attach failed: %s", exit_desc);
- else
- result.AppendError ("attach failed: process did not stop (no such process or permission problem?)");
- process->Destroy();
+ result.AppendError("no error returned from Target::Attach, and target has no process");
result.SetStatus (eReturnStatusFailed);
}
}
@@ -686,10 +637,10 @@ public:
"process continue",
"Continue execution of all threads in the current process.",
"process continue",
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresProcess |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_options(interpreter)
{
}
@@ -809,6 +760,8 @@ protected:
}
}
+ const uint32_t iohandler_id = process->GetIOHandlerID();
+
StreamString stream;
Error error;
if (synchronous_execution)
@@ -819,9 +772,9 @@ protected:
if (error.Success())
{
// There is a race condition where this thread will return up the call stack to the main command
- // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
- // a chance to call PushProcessIOHandler().
- process->SyncIOHandler(2000);
+ // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
+ // a chance to call PushProcessIOHandler().
+ process->SyncIOHandler(iohandler_id, 2000);
result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
if (synchronous_execution)
@@ -947,9 +900,9 @@ public:
"process detach",
"Detach from the current process being debugged.",
"process detach",
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched),
+ eCommandRequiresProcess |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched),
m_options(interpreter)
{
}
@@ -1228,10 +1181,10 @@ public:
"process load",
"Load a shared library into the current process.",
"process load <filename> [<filename> ...]",
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused )
+ eCommandRequiresProcess |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused )
{
}
@@ -1285,10 +1238,10 @@ public:
"process unload",
"Unload a shared library from the current process using the index returned by a previous call to \"process load\".",
"process unload <index>",
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused )
+ eCommandRequiresProcess |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused )
{
}
@@ -1349,7 +1302,7 @@ public:
"process signal",
"Send a UNIX signal to the current process being debugged.",
NULL,
- eFlagRequiresProcess | eFlagTryTargetAPILock)
+ eCommandRequiresProcess | eCommandTryTargetAPILock)
{
CommandArgumentEntry arg;
CommandArgumentData signal_arg;
@@ -1431,9 +1384,9 @@ public:
"process interrupt",
"Interrupt the current process being debugged.",
"process interrupt",
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched)
+ eCommandRequiresProcess |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched)
{
}
@@ -1493,9 +1446,9 @@ public:
"process kill",
"Terminate the current process being debugged.",
"process kill",
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched)
+ eCommandRequiresProcess |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched)
{
}
@@ -1518,7 +1471,7 @@ protected:
if (command.GetArgumentCount() == 0)
{
- Error error (process->Destroy());
+ Error error (process->Destroy(true));
if (error.Success())
{
result.SetStatus (eReturnStatusSuccessFinishResult);
@@ -1554,9 +1507,9 @@ public:
"process save-core",
"Save the current process as a core file using an appropriate file type.",
"process save-core FILE",
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched)
+ eCommandRequiresProcess |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched)
{
}
@@ -1618,7 +1571,7 @@ public:
"process status",
"Show the current status and location of executing process.",
"process status",
- eFlagRequiresProcess | eFlagTryTargetAPILock)
+ eCommandRequiresProcess | eCommandTryTargetAPILock)
{
}
@@ -1632,7 +1585,7 @@ public:
{
Stream &strm = result.GetOutputStream();
result.SetStatus (eReturnStatusSuccessFinishNoResult);
- // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
+ // No need to check "process" for validity as eCommandRequiresProcess ensures it is valid
Process *process = m_exe_ctx.GetProcessPtr();
const bool only_threads_with_stop_reason = true;
const uint32_t start_frame = 0;
@@ -1776,8 +1729,8 @@ public:
void
PrintSignalHeader (Stream &str)
{
- str.Printf ("NAME PASS STOP NOTIFY\n");
- str.Printf ("========== ===== ===== ======\n");
+ str.Printf ("NAME PASS STOP NOTIFY\n");
+ str.Printf ("=========== ===== ===== ======\n");
}
void
@@ -1787,7 +1740,7 @@ public:
bool suppress;
bool notify;
- str.Printf ("%-10s ", sig_name);
+ str.Printf ("%-11s ", sig_name);
if (signals.GetSignalInfo (signo, suppress, stop, notify))
{
bool pass = !suppress;
diff --git a/source/Commands/CommandObjectQuit.cpp b/source/Commands/CommandObjectQuit.cpp
index dd0efc61b2d0..31f82b987c1c 100644
--- a/source/Commands/CommandObjectQuit.cpp
+++ b/source/Commands/CommandObjectQuit.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectQuit.h"
// C Includes
@@ -17,6 +15,7 @@
// Project includes
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Process.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/source/Commands/CommandObjectRegister.cpp b/source/Commands/CommandObjectRegister.cpp
index 81b79b8cd8b2..fae5af42f405 100644
--- a/source/Commands/CommandObjectRegister.cpp
+++ b/source/Commands/CommandObjectRegister.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectRegister.h"
// C Includes
@@ -25,6 +23,7 @@
#include "lldb/Interpreter/Options.h"
#include "lldb/Interpreter/OptionGroupFormat.h"
#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueBoolean.h"
#include "lldb/Interpreter/OptionValueUInt64.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
@@ -47,10 +46,10 @@ public:
"register read",
"Dump the contents of one or more register values from the current frame. If no register is specified, dumps them all.",
NULL,
- eFlagRequiresFrame |
- eFlagRequiresRegContext |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresFrame |
+ eCommandRequiresRegContext |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_option_group (interpreter),
m_format_options (eFormatDefault),
m_command_options ()
@@ -143,7 +142,7 @@ public:
const RegisterSet * const reg_set = reg_ctx->GetRegisterSet(set_idx);
if (reg_set)
{
- strm.Printf ("%s:\n", reg_set->name);
+ strm.Printf ("%s:\n", (reg_set->name ? reg_set->name : "unknown") );
strm.IndentMore ();
const size_t num_registers = reg_set->num_registers;
for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx)
@@ -376,10 +375,10 @@ public:
"register write",
"Modify a single register value.",
NULL,
- eFlagRequiresFrame |
- eFlagRequiresRegContext |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused)
+ eCommandRequiresFrame |
+ eCommandRequiresRegContext |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused)
{
CommandArgumentEntry arg1;
CommandArgumentEntry arg2;
diff --git a/source/Commands/CommandObjectSettings.cpp b/source/Commands/CommandObjectSettings.cpp
index ed677afabcb5..ccbf98c767f1 100644
--- a/source/Commands/CommandObjectSettings.cpp
+++ b/source/Commands/CommandObjectSettings.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectSettings.h"
// C Includes
@@ -18,6 +16,7 @@
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
using namespace lldb;
using namespace lldb_private;
@@ -243,7 +242,7 @@ protected:
// Split the raw command into var_name and value pair.
llvm::StringRef raw_str(command);
std::string var_value_string = raw_str.split(var_name).second.str();
- const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, false, false);
Error error;
if (m_options.m_global)
diff --git a/source/Commands/CommandObjectSource.cpp b/source/Commands/CommandObjectSource.cpp
index a88a9b1f0cac..7c5f127cb51a 100644
--- a/source/Commands/CommandObjectSource.cpp
+++ b/source/Commands/CommandObjectSource.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectSource.h"
// C Includes
@@ -253,7 +251,7 @@ public:
"source list",
"Display source code (as specified) based on the current executable's debug info.",
NULL,
- eFlagRequiresTarget),
+ eCommandRequiresTarget),
m_options (interpreter)
{
}
@@ -539,9 +537,9 @@ protected:
{
SymbolContext sc;
sc_list_symbols.GetContextAtIndex (i, sc);
- if (sc.symbol)
+ if (sc.symbol && sc.symbol->ValueIsAddress())
{
- const Address &base_address = sc.symbol->GetAddress();
+ const Address &base_address = sc.symbol->GetAddressRef();
Function *function = base_address.CalculateSymbolContextFunction();
if (function)
{
@@ -690,13 +688,15 @@ protected:
bool show_module = true;
bool show_inlined_frames = true;
const bool show_function_arguments = true;
+ const bool show_function_name = true;
sc.DumpStopContext(&result.GetOutputStream(),
m_exe_ctx.GetBestExecutionContextScope(),
sc.line_entry.range.GetBaseAddress(),
show_fullpaths,
show_module,
show_inlined_frames,
- show_function_arguments);
+ show_function_arguments,
+ show_function_name);
result.GetOutputStream().EOL();
if (m_options.num_lines == 0)
diff --git a/source/Commands/CommandObjectSyntax.cpp b/source/Commands/CommandObjectSyntax.cpp
index 5093c3b99339..e9fa084fc0b5 100644
--- a/source/Commands/CommandObjectSyntax.cpp
+++ b/source/Commands/CommandObjectSyntax.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectSyntax.h"
// C Includes
diff --git a/source/Commands/CommandObjectTarget.cpp b/source/Commands/CommandObjectTarget.cpp
index 9188283966f1..448da0ede245 100644
--- a/source/Commands/CommandObjectTarget.cpp
+++ b/source/Commands/CommandObjectTarget.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectTarget.h"
// C Includes
@@ -50,6 +48,7 @@
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StackFrame.h"
@@ -388,6 +387,12 @@ protected:
core_file.GetPath(core_path, sizeof(core_path));
if (core_file.Exists())
{
+ if (!core_file.Readable())
+ {
+ result.AppendMessageWithFormat ("Core file '%s' is not readable.\n", core_path);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
FileSpec core_file_dir;
core_file_dir.GetDirectory() = core_file.GetDirectory();
target_sp->GetExecutableSearchPaths ().Append (core_file_dir);
@@ -600,10 +605,20 @@ public:
"Delete one or more targets by target index.",
NULL,
0),
- m_option_group (interpreter),
- m_cleanup_option (LLDB_OPT_SET_1, false, "clean", 'c', "Perform extra cleanup to minimize memory consumption after deleting the target.", false, false)
- {
- m_option_group.Append (&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group(interpreter),
+ m_all_option(LLDB_OPT_SET_1, false, "all", 'a', "Delete all targets.", false, true),
+ m_cleanup_option(
+ LLDB_OPT_SET_1,
+ false,
+ "clean", 'c',
+ "Perform extra cleanup to minimize memory consumption after deleting the target. "
+ "By default, LLDB will keep in memory any modules previously loaded by the target as well "
+ "as all of its debug info. Specifying --clean will unload all of these shared modules and "
+ "cause them to be reparsed again the next time the target is run",
+ false, true)
+ {
+ m_option_group.Append(&m_all_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append(&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Finalize();
}
@@ -625,90 +640,89 @@ protected:
const size_t argc = args.GetArgumentCount();
std::vector<TargetSP> delete_target_list;
TargetList &target_list = m_interpreter.GetDebugger().GetTargetList();
- bool success = true;
TargetSP target_sp;
- if (argc > 0)
+
+ if (m_all_option.GetOptionValue())
+ {
+ for (int i = 0; i < target_list.GetNumTargets(); ++i)
+ delete_target_list.push_back(target_list.GetTargetAtIndex(i));
+ }
+ else if (argc > 0)
{
const uint32_t num_targets = target_list.GetNumTargets();
// Bail out if don't have any targets.
if (num_targets == 0) {
result.AppendError("no targets to delete");
result.SetStatus(eReturnStatusFailed);
- success = false;
+ return false;
}
- for (uint32_t arg_idx = 0; success && arg_idx < argc; ++arg_idx)
+ for (uint32_t arg_idx = 0; arg_idx < argc; ++arg_idx)
{
const char *target_idx_arg = args.GetArgumentAtIndex(arg_idx);
+ bool success = false;
uint32_t target_idx = StringConvert::ToUInt32 (target_idx_arg, UINT32_MAX, 0, &success);
- if (success)
+ if (!success)
{
- if (target_idx < num_targets)
- {
- target_sp = target_list.GetTargetAtIndex (target_idx);
- if (target_sp)
- {
- delete_target_list.push_back (target_sp);
- continue;
- }
- }
- if (num_targets > 1)
- result.AppendErrorWithFormat ("target index %u is out of range, valid target indexes are 0 - %u\n",
- target_idx,
- num_targets - 1);
- else
- result.AppendErrorWithFormat("target index %u is out of range, the only valid index is 0\n",
- target_idx);
-
+ result.AppendErrorWithFormat("invalid target index '%s'\n", target_idx_arg);
result.SetStatus (eReturnStatusFailed);
- success = false;
+ return false;
}
- else
+ if (target_idx < num_targets)
{
- result.AppendErrorWithFormat("invalid target index '%s'\n", target_idx_arg);
- result.SetStatus (eReturnStatusFailed);
- success = false;
+ target_sp = target_list.GetTargetAtIndex (target_idx);
+ if (target_sp)
+ {
+ delete_target_list.push_back (target_sp);
+ continue;
+ }
}
+ if (num_targets > 1)
+ result.AppendErrorWithFormat ("target index %u is out of range, valid target indexes are 0 - %u\n",
+ target_idx,
+ num_targets - 1);
+ else
+ result.AppendErrorWithFormat("target index %u is out of range, the only valid index is 0\n",
+ target_idx);
+
+ result.SetStatus (eReturnStatusFailed);
+ return false;
}
}
else
{
target_sp = target_list.GetSelectedTarget();
- if (target_sp)
- {
- delete_target_list.push_back (target_sp);
- }
- else
+ if (!target_sp)
{
result.AppendErrorWithFormat("no target is currently selected\n");
result.SetStatus (eReturnStatusFailed);
- success = false;
+ return false;
}
+ delete_target_list.push_back (target_sp);
}
- if (success)
+
+ const size_t num_targets_to_delete = delete_target_list.size();
+ for (size_t idx = 0; idx < num_targets_to_delete; ++idx)
{
- const size_t num_targets_to_delete = delete_target_list.size();
- for (size_t idx = 0; idx < num_targets_to_delete; ++idx)
- {
- target_sp = delete_target_list[idx];
- target_list.DeleteTarget(target_sp);
- target_sp->Destroy();
- }
- // If "--clean" was specified, prune any orphaned shared modules from
- // the global shared module list
- if (m_cleanup_option.GetOptionValue ())
- {
- const bool mandatory = true;
- ModuleList::RemoveOrphanSharedModules(mandatory);
- }
- result.GetOutputStream().Printf("%u targets deleted.\n", (uint32_t)num_targets_to_delete);
- result.SetStatus(eReturnStatusSuccessFinishResult);
+ target_sp = delete_target_list[idx];
+ target_list.DeleteTarget(target_sp);
+ target_sp->Destroy();
+ }
+ // If "--clean" was specified, prune any orphaned shared modules from
+ // the global shared module list
+ if (m_cleanup_option.GetOptionValue ())
+ {
+ const bool mandatory = true;
+ ModuleList::RemoveOrphanSharedModules(mandatory);
}
+ result.GetOutputStream().Printf("%u targets deleted.\n", (uint32_t)num_targets_to_delete);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
- return result.Succeeded();
+ return true;
}
OptionGroupOptions m_option_group;
+ OptionGroupBoolean m_all_option;
OptionGroupBoolean m_cleanup_option;
};
@@ -730,7 +744,7 @@ public:
"target variable",
"Read global variable(s) prior to, or while running your binary.",
NULL,
- eFlagRequiresTarget),
+ eCommandRequiresTarget),
m_option_group (interpreter),
m_option_variable (false), // Don't include frame options
m_option_format (eFormatDefault),
@@ -773,6 +787,10 @@ public:
{
DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions());
+ if (false == valobj_sp->GetTargetSP()->GetDisplayRuntimeSupportValues() &&
+ true == valobj_sp->IsRuntimeSupportValue())
+ return;
+
switch (var_sp->GetScope())
{
case eValueTypeVariableGlobal:
@@ -1722,17 +1740,16 @@ LookupSymbolInModule (CommandInterpreter &interpreter, Stream &strm, Module *mod
DumpFullpath (strm, &module->GetFileSpec(), 0);
strm.PutCString(":\n");
strm.IndentMore ();
- //Symtab::DumpSymbolHeader (&strm);
for (i=0; i < num_matches; ++i)
{
Symbol *symbol = symtab->SymbolAtIndex(match_indexes[i]);
- DumpAddress (interpreter.GetExecutionContext().GetBestExecutionContextScope(),
- symbol->GetAddress(),
- verbose,
- strm);
-
-// strm.Indent ();
-// symbol->Dump (&strm, interpreter.GetExecutionContext().GetTargetPtr(), i);
+ if (symbol && symbol->ValueIsAddress())
+ {
+ DumpAddress (interpreter.GetExecutionContext().GetBestExecutionContextScope(),
+ symbol->GetAddressRef(),
+ verbose,
+ strm);
+ }
}
strm.IndentLess ();
return num_matches;
@@ -2547,7 +2564,7 @@ public:
"target modules dump line-table",
"Dump the line table for one or more compilation units.",
NULL,
- eFlagRequiresTarget)
+ eCommandRequiresTarget)
{
}
@@ -3462,28 +3479,24 @@ protected:
case 's':
case 'S':
{
- SymbolVendor *symbol_vendor = module->GetSymbolVendor();
+ const SymbolVendor *symbol_vendor = module->GetSymbolVendor();
if (symbol_vendor)
{
- SymbolFile *symbol_file = symbol_vendor->GetSymbolFile();
- if (symbol_file)
+ const FileSpec symfile_spec = symbol_vendor->GetMainFileSpec();
+ if (format_char == 'S')
{
- if (format_char == 'S')
+ // Dump symbol file only if different from module file
+ if (!symfile_spec || symfile_spec == module->GetFileSpec())
{
- FileSpec &symfile_spec = symbol_file->GetObjectFile()->GetFileSpec();
- // Dump symbol file only if different from module file
- if (!symfile_spec || symfile_spec == module->GetFileSpec())
- {
- print_space = false;
- break;
- }
- // Add a newline and indent past the index
- strm.Printf ("\n%*s", indent, "");
+ print_space = false;
+ break;
}
- DumpFullpath (strm, &symbol_file->GetObjectFile()->GetFileSpec(), width);
- dump_object_name = true;
- break;
+ // Add a newline and indent past the index
+ strm.Printf ("\n%*s", indent, "");
}
+ DumpFullpath (strm, &symfile_spec, width);
+ dump_object_name = true;
+ break;
}
strm.Printf("%.*s", width, "<NONE>");
}
@@ -3641,10 +3654,10 @@ public:
"target modules show-unwind",
"Show synthesized unwind instructions for a function.",
NULL,
- eFlagRequiresTarget |
- eFlagRequiresProcess |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresTarget |
+ eCommandRequiresProcess |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_options (interpreter)
{
}
@@ -3767,7 +3780,7 @@ protected:
{
result.GetOutputStream().Printf("Synchronous (restricted to call-sites) UnwindPlan is '%s'\n", callsite_unwind_plan->GetSourceName().AsCString());
}
- UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*thread.get());
+ UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*target, *thread.get());
if (fast_unwind_plan.get())
{
result.GetOutputStream().Printf("Fast UnwindPlan is '%s'\n", fast_unwind_plan->GetSourceName().AsCString());
@@ -4001,7 +4014,7 @@ public:
"target modules lookup",
"Look up information within executable and dependent shared library images.",
NULL,
- eFlagRequiresTarget),
+ eCommandRequiresTarget),
m_options (interpreter)
{
CommandArgumentEntry arg;
@@ -4381,7 +4394,7 @@ public:
CommandObjectParsed (interpreter,
"target symbols add",
"Add a debug symbol file to one of the target's current modules by specifying a path to a debug symbols file, or using the options to specify a module to download symbols for.",
- "target symbols add [<symfile>]", eFlagRequiresTarget),
+ "target symbols add [<symfile>]", eCommandRequiresTarget),
m_option_group (interpreter),
m_file_option (LLDB_OPT_SET_1, false, "shlib", 's', CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Fullpath or basename for module to find debug symbols for."),
m_current_frame_option (LLDB_OPT_SET_2, false, "frame", 'F', "Locate the debug symbols the currently selected frame.", false, true)
diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp
index 199d16b85205..5f38ad4900d6 100644
--- a/source/Commands/CommandObjectThread.cpp
+++ b/source/Commands/CommandObjectThread.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectThread.h"
// C Includes
@@ -18,6 +16,7 @@
#include "lldb/lldb-private.h"
#include "lldb/Core/State.h"
#include "lldb/Core/SourceManager.h"
+#include "lldb/Core/ValueObject.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -240,11 +239,11 @@ public:
"thread backtrace",
"Show the stack for one or more threads. If no threads are specified, show the currently selected thread. Use the thread-index \"all\" to see all threads.",
NULL,
- eFlagRequiresProcess |
- eFlagRequiresThread |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresProcess |
+ eCommandRequiresThread |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_options(interpreter)
{
}
@@ -432,6 +431,12 @@ public:
m_step_in_avoid_no_debug = eLazyBoolCalculate;
m_step_out_avoid_no_debug = eLazyBoolCalculate;
m_run_mode = eOnlyDuringStepping;
+
+ // Check if we are in Non-Stop mode
+ lldb::TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget();
+ if (target_sp.get() != nullptr && target_sp->GetNonStopModeEnabled())
+ m_run_mode = eOnlyThisThread;
+
m_avoid_regexp.clear();
m_step_in_target.clear();
m_class_name.clear();
@@ -465,11 +470,11 @@ public:
StepType step_type,
StepScope step_scope) :
CommandObjectParsed (interpreter, name, help, syntax,
- eFlagRequiresProcess |
- eFlagRequiresThread |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresProcess |
+ eCommandRequiresThread |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_step_type (step_type),
m_step_scope (step_scope),
m_options (interpreter)
@@ -579,6 +584,7 @@ protected:
if (m_step_type == eStepTypeInto)
{
StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+ assert(frame != nullptr);
if (frame->HasDebugInformation ())
{
@@ -667,6 +673,8 @@ protected:
process->GetThreadList().SetSelectedThreadByID (thread->GetID());
+ const uint32_t iohandler_id = process->GetIOHandlerID();
+
StreamString stream;
Error error;
if (synchronous_execution)
@@ -677,7 +685,7 @@ protected:
// There is a race condition where this thread will return up the call stack to the main command handler
// and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
// a chance to call PushProcessIOHandler().
- process->SyncIOHandler(2000);
+ process->SyncIOHandler(iohandler_id, 2000);
if (synchronous_execution)
{
@@ -752,10 +760,10 @@ public:
"thread continue",
"Continue execution of one or more threads in an active process.",
NULL,
- eFlagRequiresThread |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused)
+ eCommandRequiresThread |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused)
{
CommandArgumentEntry arg;
CommandArgumentData thread_idx_arg;
@@ -1064,10 +1072,10 @@ public:
"thread until",
"Run the current or specified thread until it reaches a given line number or address or leaves the current function.",
NULL,
- eFlagRequiresThread |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresThread |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_options (interpreter)
{
CommandArgumentEntry arg;
@@ -1343,10 +1351,10 @@ public:
"thread select",
"Select a thread as the currently active thread.",
NULL,
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused )
+ eCommandRequiresProcess |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused )
{
CommandArgumentEntry arg;
CommandArgumentData thread_idx_arg;
@@ -1419,10 +1427,10 @@ public:
"thread list",
"Show a summary of all current threads in a process.",
"thread list",
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused )
+ eCommandRequiresProcess |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused )
{
}
@@ -1464,10 +1472,10 @@ public:
"thread info",
"Show an extended summary of information about thread(s) in a process.",
"thread info",
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused),
+ eCommandRequiresProcess |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused),
m_options (interpreter)
{
m_add_return = false;
@@ -1656,10 +1664,10 @@ public:
"Return from the currently selected frame, short-circuiting execution of the frames below it, with an optional return value,"
" or with the -x option from the innermost function evaluation.",
"thread return",
- eFlagRequiresFrame |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresFrame |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_options (interpreter)
{
CommandArgumentEntry arg;
@@ -1884,10 +1892,10 @@ public:
"thread jump",
"Sets the program counter to a new address.",
"thread jump",
- eFlagRequiresFrame |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresFrame |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_options (interpreter)
{
}
@@ -2068,11 +2076,11 @@ public:
"Show thread plans for one or more threads. If no threads are specified, show the "
"currently selected thread. Use the thread-index \"all\" to see all threads.",
NULL,
- eFlagRequiresProcess |
- eFlagRequiresThread |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresProcess |
+ eCommandRequiresThread |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_options(interpreter)
{
}
@@ -2120,11 +2128,11 @@ public:
"Only user visible plans can be discarded, use the index from \"thread plan list\""
" without the \"-i\" argument.",
NULL,
- eFlagRequiresProcess |
- eFlagRequiresThread |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused )
+ eCommandRequiresProcess |
+ eCommandRequiresThread |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused )
{
CommandArgumentEntry arg;
CommandArgumentData plan_index_arg;
diff --git a/source/Commands/CommandObjectType.cpp b/source/Commands/CommandObjectType.cpp
index 3a4c60c00f8b..7c8061a6ca08 100644
--- a/source/Commands/CommandObjectType.cpp
+++ b/source/Commands/CommandObjectType.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectType.h"
// C Includes
@@ -4249,7 +4247,7 @@ public:
nullptr,
nullptr,
nullptr,
- eFlagRequiresFrame),
+ eCommandRequiresFrame),
m_formatter_name(formatter_name ? formatter_name : ""),
m_discovery_function(discovery_func)
{
diff --git a/source/Commands/CommandObjectVersion.cpp b/source/Commands/CommandObjectVersion.cpp
index 2d950a89c9b3..70e101c22330 100644
--- a/source/Commands/CommandObjectVersion.cpp
+++ b/source/Commands/CommandObjectVersion.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectVersion.h"
// C Includes
diff --git a/source/Commands/CommandObjectWatchpoint.cpp b/source/Commands/CommandObjectWatchpoint.cpp
index bef59ca30b3c..650fd253af02 100644
--- a/source/Commands/CommandObjectWatchpoint.cpp
+++ b/source/Commands/CommandObjectWatchpoint.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectWatchpoint.h"
#include "CommandObjectWatchpointCommand.h"
@@ -27,6 +25,7 @@
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "llvm/ADT/StringRef.h"
@@ -924,10 +923,10 @@ public:
"If watchpoint setting fails, consider disable/delete existing ones "
"to free up resources.",
NULL,
- eFlagRequiresFrame |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresFrame |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_option_group (interpreter),
m_option_watchpoint ()
{
@@ -1131,10 +1130,10 @@ public:
"If watchpoint setting fails, consider disable/delete existing ones "
"to free up resources.",
NULL,
- eFlagRequiresFrame |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused ),
+ eCommandRequiresFrame |
+ eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused ),
m_option_group (interpreter),
m_option_watchpoint ()
{
@@ -1211,7 +1210,7 @@ protected:
if (end_options)
{
- Args args (raw_command, end_options - raw_command);
+ Args args (llvm::StringRef(raw_command, end_options - raw_command));
if (!ParseOptions (args, result))
return false;
diff --git a/source/Commands/CommandObjectWatchpointCommand.cpp b/source/Commands/CommandObjectWatchpointCommand.cpp
index 275ee925adcc..d7d064e5fed9 100644
--- a/source/Commands/CommandObjectWatchpointCommand.cpp
+++ b/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
// C++ Includes
diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp
index d449d0b21438..1cd7a7447b7f 100644
--- a/source/Core/Address.cpp
+++ b/source/Core/Address.cpp
@@ -468,6 +468,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
case DumpStyleResolvedDescription:
case DumpStyleResolvedDescriptionNoModule:
case DumpStyleResolvedDescriptionNoFunctionArguments:
+ case DumpStyleNoFunctionName:
if (IsSectionOffset())
{
uint32_t pointer_size = 4;
@@ -500,7 +501,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
if (symbol_name)
{
s->PutCString(symbol_name);
- addr_t delta = file_Addr - symbol->GetAddress().GetFileAddress();
+ addr_t delta = file_Addr - symbol->GetAddressRef().GetFileAddress();
if (delta)
s->Printf(" + %" PRIu64, delta);
showed_info = true;
@@ -553,7 +554,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
#endif
Address cstr_addr(*this);
cstr_addr.SetOffset(cstr_addr.GetOffset() + pointer_size);
- func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false, true);
+ func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false, true, true);
if (ReadAddress (exe_scope, cstr_addr, pointer_size, so_addr))
{
#if VERBOSE_OUTPUT
@@ -636,7 +637,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
if (pointer_sc.function || pointer_sc.symbol)
{
s->PutCString(": ");
- pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false, true);
+ pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false, true, true);
}
}
}
@@ -662,12 +663,13 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
const bool show_fullpaths = false;
const bool show_inlined_frames = true;
const bool show_function_arguments = (style != DumpStyleResolvedDescriptionNoFunctionArguments);
+ const bool show_function_name = (style != DumpStyleNoFunctionName);
if (sc.function == NULL && sc.symbol != NULL)
{
// If we have just a symbol make sure it is in the right section
if (sc.symbol->ValueIsAddress())
{
- if (sc.symbol->GetAddress().GetSection() != GetSection())
+ if (sc.symbol->GetAddressRef().GetSection() != GetSection())
{
// don't show the module if the symbol is a trampoline symbol
show_stop_context = false;
@@ -684,7 +686,8 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
show_fullpaths,
show_module,
show_inlined_frames,
- show_function_arguments);
+ show_function_arguments,
+ show_function_name);
}
else
{
@@ -719,7 +722,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
// as our address. If it isn't, then we might have just found
// the last symbol that came before the address that we are
// looking up that has nothing to do with our address lookup.
- if (sc.symbol->ValueIsAddress() && sc.symbol->GetAddress().GetSection() != GetSection())
+ if (sc.symbol->ValueIsAddress() && sc.symbol->GetAddressRef().GetSection() != GetSection())
sc.symbol = NULL;
}
sc.GetDescription(s, eDescriptionLevelBrief, target);
@@ -742,10 +745,15 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
if (var && var->LocationIsValidForAddress (*this))
{
s->Indent();
- s->Printf (" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\", type= \"%s\", location =",
+ s->Printf (" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\"",
var->GetID(),
- var->GetName().GetCString(),
- var->GetType()->GetName().GetCString());
+ var->GetName().GetCString());
+ Type *type = var->GetType();
+ if (type)
+ s->Printf(", type = \"%s\"", type->GetName().GetCString());
+ else
+ s->PutCString(", type = <unknown>");
+ s->PutCString(", location = ");
var->DumpLocationForAddress(s, *this);
s->PutCString(", decl = ");
var->GetDeclaration().DumpStopContext(s, false);
diff --git a/source/Core/AddressResolver.cpp b/source/Core/AddressResolver.cpp
index 5369d960f251..aa457015b4fd 100644
--- a/source/Core/AddressResolver.cpp
+++ b/source/Core/AddressResolver.cpp
@@ -20,7 +20,6 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Target.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb_private;
diff --git a/source/Core/AddressResolverFileLine.cpp b/source/Core/AddressResolverFileLine.cpp
index 6089abd76cbc..e45076e9bfc6 100644
--- a/source/Core/AddressResolverFileLine.cpp
+++ b/source/Core/AddressResolverFileLine.cpp
@@ -14,7 +14,6 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/source/Core/AddressResolverName.cpp b/source/Core/AddressResolverName.cpp
index 9f3b3f506fe0..1c6205fa6bdf 100644
--- a/source/Core/AddressResolverName.cpp
+++ b/source/Core/AddressResolverName.cpp
@@ -17,7 +17,6 @@
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Symbol.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
@@ -166,7 +165,7 @@ AddressResolverName::SearchCallback
{
if (symbol_sc.symbol && symbol_sc.symbol->ValueIsAddress())
{
- if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddress())
+ if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRef())
{
sym_list.RemoveContextAtIndex(j);
continue; // Don't increment j
@@ -212,7 +211,7 @@ AddressResolverName::SearchCallback
{
if (sc.symbol && sc.symbol->ValueIsAddress())
{
- func_addr = sc.symbol->GetAddress();
+ func_addr = sc.symbol->GetAddressRef();
addr_t byte_size = sc.symbol->GetByteSize();
if (skip_prologue)
diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp
index 015f76bffbb5..33cbede9ce14 100644
--- a/source/Core/ArchSpec.cpp
+++ b/source/Core/ArchSpec.cpp
@@ -18,7 +18,7 @@
#include "llvm/Support/COFF.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/Host.h"
-#include "lldb/Utility/SafeMachO.h"
+
#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/StringList.h"
#include "lldb/Host/Endian.h"
@@ -27,6 +27,8 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/NameMatches.h"
+#include "lldb/Utility/SafeMachO.h"
#include "Plugins/Process/Utility/ARMDefines.h"
#include "Plugins/Process/Utility/InstructionUtils.h"
@@ -87,7 +89,29 @@ static const CoreDefinition g_core_definitions[] =
{ eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_armv8 , "armv8" },
{ eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_aarch64 , "aarch64" },
- { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64 , "mips64" },
+ // mips32, mips32r2, mips32r3, mips32r5, mips32r6
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32 , "mips" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r2 , "mipsr2" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r3 , "mipsr3" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r5 , "mipsr5" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r6 , "mipsr6" },
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32el , "mipsel" },
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r2el , "mipsr2el" },
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r3el , "mipsr3el" },
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r5el , "mipsr5el" },
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r6el , "mipsr6el" },
+
+ // mips64, mips64r2, mips64r3, mips64r5, mips64r6
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64 , "mips64" },
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r2 , "mips64r2" },
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r3 , "mips64r3" },
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r5 , "mips64r5" },
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r6 , "mips64r6" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64el , "mips64el" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r2el , "mips64r2el" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r3el , "mips64r3el" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r5el , "mips64r5el" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r6el , "mips64r6el" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "powerpc" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc601 , "ppc601" },
@@ -259,14 +283,25 @@ static const ArchDefinitionEntry g_elf_arch_entries[] =
{
{ ArchSpec::eCore_sparc_generic , llvm::ELF::EM_SPARC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Sparc
{ ArchSpec::eCore_x86_32_i386 , llvm::ELF::EM_386 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 80386
- { ArchSpec::eCore_x86_32_i486 , llvm::ELF::EM_486 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 486 (deprecated)
+ { ArchSpec::eCore_x86_32_i486 , llvm::ELF::EM_IAMCU , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel MCU // FIXME: is this correct?
{ ArchSpec::eCore_ppc_generic , llvm::ELF::EM_PPC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC
{ ArchSpec::eCore_ppc64_generic , llvm::ELF::EM_PPC64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC64
{ ArchSpec::eCore_arm_generic , llvm::ELF::EM_ARM , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM
{ ArchSpec::eCore_arm_aarch64 , llvm::ELF::EM_AARCH64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM64
{ ArchSpec::eCore_sparc9_generic , llvm::ELF::EM_SPARCV9, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // SPARC V9
{ ArchSpec::eCore_x86_64_x86_64 , llvm::ELF::EM_X86_64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // AMD64
- { ArchSpec::eCore_mips64 , llvm::ELF::EM_MIPS , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // MIPS
+ { ArchSpec::eCore_mips32 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32
+ { ArchSpec::eCore_mips32r2 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r2, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r2
+ { ArchSpec::eCore_mips32r6 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r6, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r6
+ { ArchSpec::eCore_mips32el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32el
+ { ArchSpec::eCore_mips32r2el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r2el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r2el
+ { ArchSpec::eCore_mips32r6el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r6el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r6el
+ { ArchSpec::eCore_mips64 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64
+ { ArchSpec::eCore_mips64r2 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r2, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r2
+ { ArchSpec::eCore_mips64r6 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r6, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r6
+ { ArchSpec::eCore_mips64el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64el
+ { ArchSpec::eCore_mips64r2el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r2el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r2el
+ { ArchSpec::eCore_mips64r6el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r6el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r6el
{ ArchSpec::eCore_hexagon_generic , llvm::ELF::EM_HEXAGON, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // HEXAGON
{ ArchSpec::eCore_kalimba3 , llvm::ELF::EM_CSR_KALIMBA, llvm::Triple::KalimbaSubArch_v3, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
{ ArchSpec::eCore_kalimba4 , llvm::ELF::EM_CSR_KALIMBA, llvm::Triple::KalimbaSubArch_v4, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
@@ -573,6 +608,32 @@ ArchSpec::GetDefaultEndian () const
return eByteOrderInvalid;
}
+bool
+ArchSpec::CharIsSignedByDefault () const
+{
+ switch (m_triple.getArch()) {
+ default:
+ return true;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ return m_triple.isOSDarwin() || m_triple.isOSWindows();
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ return m_triple.isOSDarwin();
+
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::systemz:
+ case llvm::Triple::xcore:
+ return false;
+ }
+}
+
lldb::ByteOrder
ArchSpec::GetByteOrder () const
{
@@ -779,7 +840,7 @@ ArchSpec::MergeFrom(const ArchSpec &other)
}
bool
-ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t sub)
+ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t sub, uint32_t os)
{
m_core = kCore_invalid;
bool update_triple = true;
@@ -800,7 +861,6 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su
if (arch_type == eArchTypeMachO)
{
m_triple.setVendor (llvm::Triple::Apple);
-
switch (core_def->machine)
{
case llvm::Triple::aarch64:
@@ -825,10 +885,22 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su
break;
}
}
- else
+ else if (arch_type == eArchTypeELF)
{
+ llvm::Triple::OSType ostype;
+ switch (os)
+ {
+ case llvm::ELF::ELFOSABI_AIX: ostype = llvm::Triple::OSType::AIX; break;
+ case llvm::ELF::ELFOSABI_FREEBSD: ostype = llvm::Triple::OSType::FreeBSD; break;
+ case llvm::ELF::ELFOSABI_GNU: ostype = llvm::Triple::OSType::Linux; break;
+ case llvm::ELF::ELFOSABI_NETBSD: ostype = llvm::Triple::OSType::NetBSD; break;
+ case llvm::ELF::ELFOSABI_OPENBSD: ostype = llvm::Triple::OSType::OpenBSD; break;
+ case llvm::ELF::ELFOSABI_SOLARIS: ostype = llvm::Triple::OSType::Solaris; break;
+ default:
+ ostype = llvm::Triple::OSType::UnknownOS;
+ }
+ m_triple.setOS (ostype);
m_triple.setVendor (llvm::Triple::UnknownVendor);
- m_triple.setOS (llvm::Triple::UnknownOS);
}
// Fall back onto setting the machine type if the arch by name failed...
if (m_triple.getArch () == llvm::Triple::UnknownArch)
@@ -1019,6 +1091,8 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
try_inverse = false;
if (core2 == ArchSpec::eCore_arm_armv7)
return true;
+ if (core2 == ArchSpec::eCore_arm_armv6m)
+ return true;
}
break;
@@ -1027,8 +1101,36 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
return true;
break;
- case ArchSpec::eCore_arm_armv7m:
case ArchSpec::eCore_arm_armv7em:
+ if (!enforce_exact_match)
+ {
+ if (core2 == ArchSpec::eCore_arm_generic)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7m)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv6m)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7)
+ return true;
+ try_inverse = true;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7m:
+ if (!enforce_exact_match)
+ {
+ if (core2 == ArchSpec::eCore_arm_generic)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv6m)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7em)
+ return true;
+ try_inverse = true;
+ }
+ break;
+
case ArchSpec::eCore_arm_armv7f:
case ArchSpec::eCore_arm_armv7k:
case ArchSpec::eCore_arm_armv7s:
@@ -1084,6 +1186,36 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
}
break;
+ case ArchSpec::eCore_mips64:
+ case ArchSpec::eCore_mips64r2:
+ case ArchSpec::eCore_mips64r3:
+ case ArchSpec::eCore_mips64r5:
+ case ArchSpec::eCore_mips64r6:
+ if (!enforce_exact_match)
+ {
+ if (core2 >= ArchSpec::kCore_mips32_first && core2 <= (core1 - 10))
+ return true;
+ if (core2 >= ArchSpec::kCore_mips64_first && core2 <= (core1 - 1))
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_mips64el:
+ case ArchSpec::eCore_mips64r2el:
+ case ArchSpec::eCore_mips64r3el:
+ case ArchSpec::eCore_mips64r5el:
+ case ArchSpec::eCore_mips64r6el:
+ if (!enforce_exact_match)
+ {
+ if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= (core1 - 10))
+ return true;
+ if (core2 >= ArchSpec::kCore_mips64el_first && core2 <= (core1 - 1))
+ return true;
+ try_inverse = false;
+ }
+ break;
+
default:
break;
}
diff --git a/source/Core/Broadcaster.cpp b/source/Core/Broadcaster.cpp
index 1cbbde20e7f6..351487401f6b 100644
--- a/source/Core/Broadcaster.cpp
+++ b/source/Core/Broadcaster.cpp
@@ -16,7 +16,6 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/StreamString.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/source/Core/Communication.cpp b/source/Core/Communication.cpp
index ea84843fe0b3..ae579d1b00ae 100644
--- a/source/Core/Communication.cpp
+++ b/source/Core/Communication.cpp
@@ -11,7 +11,6 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Communication.h"
#include "lldb/Core/Connection.h"
#include "lldb/Core/Log.h"
@@ -39,9 +38,11 @@ Communication::Communication(const char *name) :
Broadcaster (NULL, name),
m_connection_sp (),
m_read_thread_enabled (false),
+ m_read_thread_did_exit (false),
m_bytes(),
m_bytes_mutex (Mutex::eMutexTypeRecursive),
m_write_mutex (Mutex::eMutexTypeNormal),
+ m_synchronize_mutex (Mutex::eMutexTypeNormal),
m_callback (NULL),
m_callback_baton (NULL),
m_close_on_eof (true)
@@ -56,6 +57,7 @@ Communication::Communication(const char *name) :
SetEventName (eBroadcastBitReadThreadDidExit, "read thread did exit");
SetEventName (eBroadcastBitReadThreadShouldExit, "read thread should exit");
SetEventName (eBroadcastBitPacketAvailable, "packet available");
+ SetEventName (eBroadcastBitNoMorePendingInput, "no more pending input");
CheckInWithManager();
}
@@ -182,7 +184,8 @@ Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, Connectio
if (event_type & eBroadcastBitReadThreadDidExit)
{
- Disconnect (NULL);
+ if (GetCloseOnEOF ())
+ Disconnect (NULL);
break;
}
}
@@ -244,6 +247,7 @@ Communication::StartReadThread (Error *error_ptr)
snprintf(thread_name, sizeof(thread_name), "<lldb.comm.%s>", m_broadcaster_name.AsCString());
m_read_thread_enabled = true;
+ m_read_thread_did_exit = false;
m_read_thread = ThreadLauncher::LaunchThread(thread_name, Communication::ReadThread, this, error_ptr);
if (!m_read_thread.IsJoinable())
m_read_thread_enabled = false;
@@ -376,9 +380,8 @@ Communication::ReadThread (lldb::thread_arg_t p)
break;
case eConnectionStatusEndOfFile:
- if (comm->GetCloseOnEOF())
- done = true;
- break;
+ done = true;
+ break;
case eConnectionStatusError: // Check GetError() for details
if (error.GetType() == eErrorTypePOSIX && error.GetError() == EIO)
{
@@ -392,9 +395,13 @@ Communication::ReadThread (lldb::thread_arg_t p)
p,
Communication::ConnectionStatusAsCString (status));
break;
+ case eConnectionStatusInterrupted: // Synchronization signal from SynchronizeWithReadThread()
+ // The connection returns eConnectionStatusInterrupted only when there is no
+ // input pending to be read, so we can signal that.
+ comm->BroadcastEvent (eBroadcastBitNoMorePendingInput);
+ break;
case eConnectionStatusNoConnection: // No connection
case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
- case eConnectionStatusInterrupted: // Interrupted
done = true;
// Fall through...
case eConnectionStatusTimedOut: // Request timed out
@@ -410,7 +417,9 @@ Communication::ReadThread (lldb::thread_arg_t p)
if (log)
log->Printf ("%p Communication::ReadThread () thread exiting...", p);
+ comm->m_read_thread_did_exit = true;
// Let clients know that this thread is exiting
+ comm->BroadcastEvent (eBroadcastBitNoMorePendingInput);
comm->BroadcastEvent (eBroadcastBitReadThreadDidExit);
return NULL;
}
@@ -427,6 +436,28 @@ Communication::SetReadThreadBytesReceivedCallback
}
void
+Communication::SynchronizeWithReadThread ()
+{
+ // Only one thread can do the synchronization dance at a time.
+ Mutex::Locker locker(m_synchronize_mutex);
+
+ // First start listening for the synchronization event.
+ Listener listener("Communication::SyncronizeWithReadThread");
+ listener.StartListeningForEvents(this, eBroadcastBitNoMorePendingInput);
+
+ // If the thread is not running, there is no point in synchronizing.
+ if (!m_read_thread_enabled || m_read_thread_did_exit)
+ return;
+
+ // Notify the read thread.
+ m_connection_sp->InterruptRead();
+
+ // Wait for the synchronization event.
+ EventSP event_sp;
+ listener.WaitForEvent(NULL, event_sp);
+}
+
+void
Communication::SetConnection (Connection *connection)
{
Disconnect (NULL);
diff --git a/source/Core/ConnectionMachPort.cpp b/source/Core/ConnectionMachPort.cpp
index fe29814be420..e04c48905570 100644
--- a/source/Core/ConnectionMachPort.cpp
+++ b/source/Core/ConnectionMachPort.cpp
@@ -17,7 +17,6 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Communication.h"
#include "lldb/Core/Log.h"
@@ -69,7 +68,7 @@ ConnectionMachPort::Connect (const char *s, Error *error_ptr)
ConnectionStatus status = eConnectionStatusError;
- if (strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://")))
+ if (0 == strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://")))
{
s += strlen("bootstrap-checkin://");
@@ -83,7 +82,7 @@ ConnectionMachPort::Connect (const char *s, Error *error_ptr)
error_ptr->SetErrorString ("bootstrap port name is empty");
}
}
- else if (strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://")))
+ else if (0 == strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://")))
{
s += strlen("bootstrap-lookup://");
if (*s)
diff --git a/source/Core/ConnectionSharedMemory.cpp b/source/Core/ConnectionSharedMemory.cpp
index d3dfa3cd8d56..77daeb14840d 100644
--- a/source/Core/ConnectionSharedMemory.cpp
+++ b/source/Core/ConnectionSharedMemory.cpp
@@ -26,7 +26,6 @@
// Other libraries and framework includes
// Project includes
#include "llvm/Support/MathExtras.h"
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Communication.h"
#include "lldb/Core/Log.h"
diff --git a/source/Core/CxaDemangle.cpp b/source/Core/CxaDemangle.cpp
new file mode 100644
index 000000000000..bcc52ff39fe4
--- /dev/null
+++ b/source/Core/CxaDemangle.cpp
@@ -0,0 +1,5011 @@
+//----------------------------------------------------------------------
+// Inlined copy of:
+// http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp
+// revision 238263.
+//
+// Changes include:
+// - Renamed the "__cxxabiv1" namespace to "lldb_private"
+// - Stripped GCC attributes()
+// - Removed extern "C" from the cxa_demangle function
+// - Added "#undef _LIBCPP_EXTERN_TEMPLATE" to avoid warning
+// - Implemented missing rebind, construct, destroy in malloc_alloc
+// - Replaced noexcept, constexpr, alignas with their LLVM_* equivalents
+// - Included win32.h for snprintf implementation for MSVC
+// - Removed constexpr member initialization for MSVC
+// - Changed argument to alignas() to a literal for MSVC
+//----------------------------------------------------------------------
+
+#if defined(_MSC_VER)
+#include "lldb/Host/windows/win32.h" // snprintf
+#endif
+#include "llvm/Support/Compiler.h" // LLVM_{NOEXCEPT, CONSTEXPR, ALIGNAS}
+#undef _LIBCPP_EXTERN_TEMPLATE // Avoid warning below
+
+//===-------------------------- cxa_demangle.cpp --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define _LIBCPP_EXTERN_TEMPLATE(...)
+#define _LIBCPP_NO_EXCEPTIONS
+
+#include <vector>
+#include <algorithm>
+#include <string>
+#include <numeric>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
+
+namespace lldb_private
+{
+
+namespace
+{
+
+enum
+{
+ unknown_error = -4,
+ invalid_args = -3,
+ invalid_mangled_name,
+ memory_alloc_failure,
+ success
+};
+
+template <class C>
+ const char* parse_type(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_encoding(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args = 0);
+template <class C>
+ const char* parse_expression(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_template_args(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_operator_name(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_unqualified_name(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_decltype(const char* first, const char* last, C& db);
+
+template <class C>
+void
+print_stack(const C& db)
+{
+ fprintf(stderr, "---------\n");
+ fprintf(stderr, "names:\n");
+ for (auto& s : db.names)
+ fprintf(stderr, "{%s#%s}\n", s.first.c_str(), s.second.c_str());
+ int i = -1;
+ fprintf(stderr, "subs:\n");
+ for (auto& v : db.subs)
+ {
+ if (i >= 0)
+ fprintf(stderr, "S%i_ = {", i);
+ else
+ fprintf(stderr, "S_ = {");
+ for (auto& s : v)
+ fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str());
+ fprintf(stderr, "}\n");
+ ++i;
+ }
+ fprintf(stderr, "template_param:\n");
+ for (auto& t : db.template_param)
+ {
+ fprintf(stderr, "--\n");
+ i = -1;
+ for (auto& v : t)
+ {
+ if (i >= 0)
+ fprintf(stderr, "T%i_ = {", i);
+ else
+ fprintf(stderr, "T_ = {");
+ for (auto& s : v)
+ fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str());
+ fprintf(stderr, "}\n");
+ ++i;
+ }
+ }
+ fprintf(stderr, "---------\n\n");
+}
+
+template <class C>
+void
+print_state(const char* msg, const char* first, const char* last, const C& db)
+{
+ fprintf(stderr, "%s: ", msg);
+ for (; first != last; ++first)
+ fprintf(stderr, "%c", *first);
+ fprintf(stderr, "\n");
+ print_stack(db);
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+
+const char*
+parse_number(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ const char* t = first;
+ if (*t == 'n')
+ ++t;
+ if (t != last)
+ {
+ if (*t == '0')
+ {
+ first = t+1;
+ }
+ else if ('1' <= *t && *t <= '9')
+ {
+ first = t+1;
+ while (first != last && std::isdigit(*first))
+ ++first;
+ }
+ }
+ }
+ return first;
+}
+
+template <class Float>
+struct float_data;
+
+template <>
+struct float_data<float>
+{
+ static const size_t mangled_size = 8;
+ static const size_t max_demangled_size = 24;
+ static const char* spec;
+};
+
+const char* float_data<float>::spec = "%af";
+
+template <>
+struct float_data<double>
+{
+ static const size_t mangled_size = 16;
+ static const size_t max_demangled_size = 32;
+ static const char* spec;
+};
+
+const char* float_data<double>::spec = "%a";
+
+template <>
+struct float_data<long double>
+{
+#if defined(__arm__)
+ static const size_t mangled_size = 16;
+#else
+ static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
+#endif
+ static const size_t max_demangled_size = 40;
+ static const char* spec;
+};
+
+const char* float_data<long double>::spec = "%LaL";
+
+template <class Float, class C>
+const char*
+parse_floating_number(const char* first, const char* last, C& db)
+{
+ const size_t N = float_data<Float>::mangled_size;
+ if (static_cast<std::size_t>(last - first) > N)
+ {
+ last = first + N;
+ union
+ {
+ Float value;
+ char buf[sizeof(Float)];
+ };
+ const char* t = first;
+ char* e = buf;
+ for (; t != last; ++t, ++e)
+ {
+ if (!isxdigit(*t))
+ return first;
+ unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+ static_cast<unsigned>(*t - 'a' + 10);
+ ++t;
+ unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+ static_cast<unsigned>(*t - 'a' + 10);
+ *e = static_cast<char>((d1 << 4) + d0);
+ }
+ if (*t == 'E')
+ {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ std::reverse(buf, e);
+#endif
+ char num[float_data<Float>::max_demangled_size] = {0};
+ int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);
+ if (static_cast<std::size_t>(n) >= sizeof(num))
+ return first;
+ db.names.push_back(typename C::String(num, static_cast<std::size_t>(n)));
+ first = t+1;
+ }
+ }
+ return first;
+}
+
+// <source-name> ::= <positive length number> <identifier>
+
+template <class C>
+const char*
+parse_source_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ char c = *first;
+ if (isdigit(c) && first+1 != last)
+ {
+ const char* t = first+1;
+ size_t n = static_cast<size_t>(c - '0');
+ for (c = *t; isdigit(c); c = *t)
+ {
+ n = n * 10 + static_cast<size_t>(c - '0');
+ if (++t == last)
+ return first;
+ }
+ if (static_cast<size_t>(last - t) >= n)
+ {
+ typename C::String r(t, n);
+ if (r.substr(0, 10) == "_GLOBAL__N")
+ db.names.push_back("(anonymous namespace)");
+ else
+ db.names.push_back(std::move(r));
+ first = t + n;
+ }
+ }
+ }
+ return first;
+}
+
+// <substitution> ::= S <seq-id> _
+// ::= S_
+// <substitution> ::= Sa # ::std::allocator
+// <substitution> ::= Sb # ::std::basic_string
+// <substitution> ::= Ss # ::std::basic_string < char,
+// ::std::char_traits<char>,
+// ::std::allocator<char> >
+// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
+// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
+// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+
+template <class C>
+const char*
+parse_substitution(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if (*first == 'S')
+ {
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("std::allocator");
+ first += 2;
+ break;
+ case 'b':
+ db.names.push_back("std::basic_string");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("std::string");
+ first += 2;
+ break;
+ case 'i':
+ db.names.push_back("std::istream");
+ first += 2;
+ break;
+ case 'o':
+ db.names.push_back("std::ostream");
+ first += 2;
+ break;
+ case 'd':
+ db.names.push_back("std::iostream");
+ first += 2;
+ break;
+ case '_':
+ if (!db.subs.empty())
+ {
+ for (const auto& n : db.subs.front())
+ db.names.push_back(n);
+ first += 2;
+ }
+ break;
+ default:
+ if (std::isdigit(first[1]) || std::isupper(first[1]))
+ {
+ size_t sub = 0;
+ const char* t = first+1;
+ if (std::isdigit(*t))
+ sub = static_cast<size_t>(*t - '0');
+ else
+ sub = static_cast<size_t>(*t - 'A') + 10;
+ for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
+ {
+ sub *= 36;
+ if (std::isdigit(*t))
+ sub += static_cast<size_t>(*t - '0');
+ else
+ sub += static_cast<size_t>(*t - 'A') + 10;
+ }
+ if (t == last || *t != '_')
+ return first;
+ ++sub;
+ if (sub < db.subs.size())
+ {
+ for (const auto& n : db.subs[sub])
+ db.names.push_back(n);
+ first = t+1;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <builtin-type> ::= v # void
+// ::= w # wchar_t
+// ::= b # bool
+// ::= c # char
+// ::= a # signed char
+// ::= h # unsigned char
+// ::= s # short
+// ::= t # unsigned short
+// ::= i # int
+// ::= j # unsigned int
+// ::= l # long
+// ::= m # unsigned long
+// ::= x # long long, __int64
+// ::= y # unsigned long long, __int64
+// ::= n # __int128
+// ::= o # unsigned __int128
+// ::= f # float
+// ::= d # double
+// ::= e # long double, __float80
+// ::= g # __float128
+// ::= z # ellipsis
+// ::= Dd # IEEE 754r decimal floating point (64 bits)
+// ::= De # IEEE 754r decimal floating point (128 bits)
+// ::= Df # IEEE 754r decimal floating point (32 bits)
+// ::= Dh # IEEE 754r half-precision floating point (16 bits)
+// ::= Di # char32_t
+// ::= Ds # char16_t
+// ::= Da # auto (in dependent new-expressions)
+// ::= Dc # decltype(auto)
+// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+// ::= u <source-name> # vendor extended type
+
+template <class C>
+const char*
+parse_builtin_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'v':
+ db.names.push_back("void");
+ ++first;
+ break;
+ case 'w':
+ db.names.push_back("wchar_t");
+ ++first;
+ break;
+ case 'b':
+ db.names.push_back("bool");
+ ++first;
+ break;
+ case 'c':
+ db.names.push_back("char");
+ ++first;
+ break;
+ case 'a':
+ db.names.push_back("signed char");
+ ++first;
+ break;
+ case 'h':
+ db.names.push_back("unsigned char");
+ ++first;
+ break;
+ case 's':
+ db.names.push_back("short");
+ ++first;
+ break;
+ case 't':
+ db.names.push_back("unsigned short");
+ ++first;
+ break;
+ case 'i':
+ db.names.push_back("int");
+ ++first;
+ break;
+ case 'j':
+ db.names.push_back("unsigned int");
+ ++first;
+ break;
+ case 'l':
+ db.names.push_back("long");
+ ++first;
+ break;
+ case 'm':
+ db.names.push_back("unsigned long");
+ ++first;
+ break;
+ case 'x':
+ db.names.push_back("long long");
+ ++first;
+ break;
+ case 'y':
+ db.names.push_back("unsigned long long");
+ ++first;
+ break;
+ case 'n':
+ db.names.push_back("__int128");
+ ++first;
+ break;
+ case 'o':
+ db.names.push_back("unsigned __int128");
+ ++first;
+ break;
+ case 'f':
+ db.names.push_back("float");
+ ++first;
+ break;
+ case 'd':
+ db.names.push_back("double");
+ ++first;
+ break;
+ case 'e':
+ db.names.push_back("long double");
+ ++first;
+ break;
+ case 'g':
+ db.names.push_back("__float128");
+ ++first;
+ break;
+ case 'z':
+ db.names.push_back("...");
+ ++first;
+ break;
+ case 'u':
+ {
+ const char*t = parse_source_name(first+1, last, db);
+ if (t != first+1)
+ first = t;
+ }
+ break;
+ case 'D':
+ if (first+1 != last)
+ {
+ switch (first[1])
+ {
+ case 'd':
+ db.names.push_back("decimal64");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("decimal128");
+ first += 2;
+ break;
+ case 'f':
+ db.names.push_back("decimal32");
+ first += 2;
+ break;
+ case 'h':
+ db.names.push_back("decimal16");
+ first += 2;
+ break;
+ case 'i':
+ db.names.push_back("char32_t");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("char16_t");
+ first += 2;
+ break;
+ case 'a':
+ db.names.push_back("auto");
+ first += 2;
+ break;
+ case 'c':
+ db.names.push_back("decltype(auto)");
+ first += 2;
+ break;
+ case 'n':
+ db.names.push_back("std::nullptr_t");
+ first += 2;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+
+const char*
+parse_cv_qualifiers(const char* first, const char* last, unsigned& cv)
+{
+ cv = 0;
+ if (first != last)
+ {
+ if (*first == 'r')
+ {
+ cv |= 4;
+ ++first;
+ }
+ if (*first == 'V')
+ {
+ cv |= 2;
+ ++first;
+ }
+ if (*first == 'K')
+ {
+ cv |= 1;
+ ++first;
+ }
+ }
+ return first;
+}
+
+// <template-param> ::= T_ # first template parameter
+// ::= T <parameter-2 non-negative number> _
+
+template <class C>
+const char*
+parse_template_param(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if (*first == 'T')
+ {
+ if (first[1] == '_')
+ {
+ if (db.template_param.empty())
+ return first;
+ if (!db.template_param.back().empty())
+ {
+ for (auto& t : db.template_param.back().front())
+ db.names.push_back(t);
+ first += 2;
+ }
+ else
+ {
+ db.names.push_back("T_");
+ first += 2;
+ db.fix_forward_references = true;
+ }
+ }
+ else if (isdigit(first[1]))
+ {
+ const char* t = first+1;
+ size_t sub = static_cast<size_t>(*t - '0');
+ for (++t; t != last && isdigit(*t); ++t)
+ {
+ sub *= 10;
+ sub += static_cast<size_t>(*t - '0');
+ }
+ if (t == last || *t != '_' || db.template_param.empty())
+ return first;
+ ++sub;
+ if (sub < db.template_param.back().size())
+ {
+ for (auto& temp : db.template_param.back()[sub])
+ db.names.push_back(temp);
+ first = t+1;
+ }
+ else
+ {
+ db.names.push_back(typename C::String(first, t+1));
+ first = t+1;
+ db.fix_forward_references = true;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// cc <type> <expression> # const_cast<type> (expression)
+
+template <class C>
+const char*
+parse_const_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// dc <type> <expression> # dynamic_cast<type> (expression)
+
+template <class C>
+const char*
+parse_dynamic_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// rc <type> <expression> # reinterpret_cast<type> (expression)
+
+template <class C>
+const char*
+parse_reinterpret_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// sc <type> <expression> # static_cast<type> (expression)
+
+template <class C>
+const char*
+parse_static_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// sp <expression> # pack expansion
+
+template <class C>
+const char*
+parse_pack_expansion(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ return first;
+}
+
+// st <type> # sizeof (a type)
+
+template <class C>
+const char*
+parse_sizeof_type_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 't')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// sz <expr> # sizeof (a expression)
+
+template <class C>
+const char*
+parse_sizeof_expr_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'z')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// sZ <template-param> # size of a parameter pack
+
+template <class C>
+const char*
+parse_sizeof_param_pack_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
+ {
+ size_t k0 = db.names.size();
+ const char* t = parse_template_param(first+2, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+2)
+ {
+ typename C::String tmp("sizeof...(");
+ size_t k = k0;
+ if (k != k1)
+ {
+ tmp += db.names[k].move_full();
+ for (++k; k != k1; ++k)
+ tmp += ", " + db.names[k].move_full();
+ }
+ tmp += ")";
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ db.names.push_back(std::move(tmp));
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter
+// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
+// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter
+// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
+
+template <class C>
+const char*
+parse_function_param(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && *first == 'f')
+ {
+ if (first[1] == 'p')
+ {
+ unsigned cv;
+ const char* t = parse_cv_qualifiers(first+2, last, cv);
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ db.names.push_back("fp" + typename C::String(t, t1));
+ first = t1+1;
+ }
+ }
+ else if (first[1] == 'L')
+ {
+ unsigned cv;
+ const char* t0 = parse_number(first+2, last);
+ if (t0 != last && *t0 == 'p')
+ {
+ ++t0;
+ const char* t = parse_cv_qualifiers(t0, last, cv);
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ db.names.push_back("fp" + typename C::String(t, t1));
+ first = t1+1;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// sZ <function-param> # size of a function parameter pack
+
+template <class C>
+const char*
+parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
+ {
+ const char* t = parse_function_param(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// te <expression> # typeid (expression)
+// ti <type> # typeid (type)
+
+template <class C>
+const char*
+parse_typeid_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))
+ {
+ const char* t;
+ if (first[1] == 'e')
+ t = parse_expression(first+2, last, db);
+ else
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "typeid(" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// tw <expression> # throw expression
+
+template <class C>
+const char*
+parse_throw_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "throw " + db.names.back().move_full();
+ first = t;
+ }
+ }
+ return first;
+}
+
+// ds <expression> <expression> # expr.*expr
+
+template <class C>
+const char*
+parse_dot_star_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += ".*" + expr;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// <simple-id> ::= <source-name> [ <template-args> ]
+
+template <class C>
+const char*
+parse_simple_id(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = parse_source_name(first, last, db);
+ if (t != first)
+ {
+ const char* t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ first = t1;
+ }
+ else
+ first = t;
+ }
+ return first;
+}
+
+// <unresolved-type> ::= <template-param>
+// ::= <decltype>
+// ::= <substitution>
+
+template <class C>
+const char*
+parse_unresolved_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = first;
+ switch (*first)
+ {
+ case 'T':
+ {
+ size_t k0 = db.names.size();
+ t = parse_template_param(first, last, db);
+ size_t k1 = db.names.size();
+ if (t != first && k1 == k0 + 1)
+ {
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ else
+ {
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ }
+ break;
+ }
+ case 'D':
+ t = parse_decltype(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ break;
+ case 'S':
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ first = t;
+ else
+ {
+ if (last - first > 2 && first[1] == 't')
+ {
+ t = parse_unqualified_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "std::");
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
+// ::= <simple-id> # e.g., ~A<2*N>
+
+template <class C>
+const char*
+parse_destructor_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = parse_unresolved_type(first, last, db);
+ if (t == first)
+ t = parse_simple_id(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "~");
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <base-unresolved-name> ::= <simple-id> # unresolved name
+// extension ::= <operator-name> # unresolved operator-function-id
+// extension ::= <operator-name> <template-args> # unresolved operator template-id
+// ::= on <operator-name> # unresolved operator-function-id
+// ::= on <operator-name> <template-args> # unresolved operator template-id
+// ::= dn <destructor-name> # destructor or pseudo-destructor;
+// # e.g. ~X or ~X<N-1>
+
+template <class C>
+const char*
+parse_base_unresolved_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
+ {
+ if (first[0] == 'o')
+ {
+ const char* t = parse_operator_name(first+2, last, db);
+ if (t != first+2)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ }
+ }
+ else
+ {
+ const char* t = parse_destructor_name(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ }
+ else
+ {
+ const char* t = parse_simple_id(first, last, db);
+ if (t == first)
+ {
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ }
+ }
+ else
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <unresolved-qualifier-level> ::= <simple-id>
+
+template <class C>
+const char*
+parse_unresolved_qualifier_level(const char* first, const char* last, C& db)
+{
+ return parse_simple_id(first, last, db);
+}
+
+// <unresolved-name>
+// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
+// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
+// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+// # A::x, N::y, A<T>::z; "gs" means leading "::"
+// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
+// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
+// # T::N::x /decltype(p)::N::x
+// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
+
+template <class C>
+const char*
+parse_unresolved_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2)
+ {
+ const char* t = first;
+ bool global = false;
+ if (t[0] == 'g' && t[1] == 's')
+ {
+ global = true;
+ t += 2;
+ }
+ const char* t2 = parse_base_unresolved_name(t, last, db);
+ if (t2 != t)
+ {
+ if (global)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "::");
+ }
+ first = t2;
+ }
+ else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
+ {
+ if (t[2] == 'N')
+ {
+ t += 3;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ t = t1;
+ if (t == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ else
+ {
+ t += 2;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 != t)
+ {
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ t = t1;
+ }
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ else
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ if (global)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "::");
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// dt <expression> <unresolved-name> # expr.name
+
+template <class C>
+const char*
+parse_dot_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_unresolved_name(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "." + name;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// cl <expression>+ E # call
+
+template <class C>
+const char*
+parse_call_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (t == last)
+ return first;
+ if (db.names.empty())
+ return first;
+ db.names.back().first += db.names.back().second;
+ db.names.back().second = typename C::String();
+ db.names.back().first.append("(");
+ bool first_expr = true;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ if (!first_expr)
+ {
+ db.names.back().first.append(", ");
+ first_expr = false;
+ }
+ db.names.back().first.append(tmp);
+ }
+ t = t1;
+ }
+ ++t;
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(")");
+ first = t;
+ }
+ }
+ return first;
+}
+
+// [gs] nw <expression>* _ <type> E # new (expr-list) type
+// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+// [gs] na <expression>* _ <type> E # new[] (expr-list) type
+// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+// <initializer> ::= pi <expression>* E # parenthesized initialization
+
+template <class C>
+const char*
+parse_new_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4)
+ {
+ const char* t = first;
+ bool parsed_gs = false;
+ if (t[0] == 'g' && t[1] == 's')
+ {
+ t += 2;
+ parsed_gs = true;
+ }
+ if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a'))
+ {
+ bool is_array = t[1] == 'a';
+ t += 2;
+ if (t == last)
+ return first;
+ bool has_expr_list = false;
+ bool first_expr = true;
+ while (*t != '_')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ has_expr_list = true;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ ++t;
+ const char* t1 = parse_type(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ bool has_init = false;
+ if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')
+ {
+ t += 2;
+ has_init = true;
+ first_expr = true;
+ while (*t != 'E')
+ {
+ t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ }
+ if (*t != 'E')
+ return first;
+ typename C::String init_list;
+ if (has_init)
+ {
+ if (db.names.empty())
+ return first;
+ init_list = db.names.back().move_full();
+ db.names.pop_back();
+ }
+ if (db.names.empty())
+ return first;
+ auto type = db.names.back().move_full();
+ db.names.pop_back();
+ typename C::String expr_list;
+ if (has_expr_list)
+ {
+ if (db.names.empty())
+ return first;
+ expr_list = db.names.back().move_full();
+ db.names.pop_back();
+ }
+ typename C::String r;
+ if (parsed_gs)
+ r = "::";
+ if (is_array)
+ r += "[] ";
+ else
+ r += " ";
+ if (has_expr_list)
+ r += "(" + expr_list + ") ";
+ r += type;
+ if (has_init)
+ r += " (" + init_list + ")";
+ db.names.push_back(std::move(r));
+ first = t+1;
+ }
+ }
+ return first;
+}
+
+// cv <type> <expression> # conversion with one argument
+// cv <type> _ <expression>* E # conversion with a different number of arguments
+
+template <class C>
+const char*
+parse_conversion_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
+ {
+ bool try_to_parse_template_args = db.try_to_parse_template_args;
+ db.try_to_parse_template_args = false;
+ const char* t = parse_type(first+2, last, db);
+ db.try_to_parse_template_args = try_to_parse_template_args;
+ if (t != first+2 && t != last)
+ {
+ if (*t != '_')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t)
+ return first;
+ t = t1;
+ }
+ else
+ {
+ ++t;
+ if (t == last)
+ return first;
+ if (*t == 'E')
+ db.names.emplace_back();
+ else
+ {
+ bool first_expr = true;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ }
+ ++t;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// pt <expression> <expression> # expr->name
+
+template <class C>
+const char*
+parse_arrow_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "->";
+ db.names.back().first += tmp;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// <ref-qualifier> ::= R # & ref-qualifier
+// <ref-qualifier> ::= O # && ref-qualifier
+
+// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+
+template <class C>
+const char*
+parse_function_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'F')
+ {
+ const char* t = first+1;
+ if (t != last)
+ {
+ if (*t == 'Y')
+ {
+ /* extern "C" */
+ if (++t == last)
+ return first;
+ }
+ const char* t1 = parse_type(t, last, db);
+ if (t1 != t)
+ {
+ t = t1;
+ typename C::String sig("(");
+ int ref_qual = 0;
+ while (true)
+ {
+ if (t == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (*t == 'E')
+ {
+ ++t;
+ break;
+ }
+ if (*t == 'v')
+ {
+ ++t;
+ continue;
+ }
+ if (*t == 'R' && t+1 != last && t[1] == 'E')
+ {
+ ref_qual = 1;
+ ++t;
+ continue;
+ }
+ if (*t == 'O' && t+1 != last && t[1] == 'E')
+ {
+ ref_qual = 2;
+ ++t;
+ continue;
+ }
+ size_t k0 = db.names.size();
+ t1 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t1 == t || t1 == last)
+ return first;
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (sig.size() > 1)
+ sig += ", ";
+ sig += db.names[k].move_full();
+ }
+ for (size_t k = k0; k < k1; ++k)
+ db.names.pop_back();
+ t = t1;
+ }
+ sig += ")";
+ switch (ref_qual)
+ {
+ case 1:
+ sig += " &";
+ break;
+ case 2:
+ sig += " &&";
+ break;
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " ";
+ db.names.back().second.insert(0, sig);
+ first = t;
+ }
+ }
+ }
+ return first;
+}
+
+// <pointer-to-member-type> ::= M <class type> <member type>
+
+template <class C>
+const char*
+parse_pointer_to_member_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'M')
+ {
+ const char* t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ const char* t2 = parse_type(t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto func = std::move(db.names.back());
+ db.names.pop_back();
+ auto class_type = std::move(db.names.back());
+ if (!func.second.empty() && func.second.front() == '(')
+ {
+ db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*";
+ db.names.back().second = ")" + std::move(func.second);
+ }
+ else
+ {
+ db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*";
+ db.names.back().second = std::move(func.second);
+ }
+ first = t2;
+ }
+ }
+ }
+ return first;
+}
+
+// <array-type> ::= A <positive dimension number> _ <element type>
+// ::= A [<dimension expression>] _ <element type>
+
+template <class C>
+const char*
+parse_array_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'A' && first+1 != last)
+ {
+ if (first[1] == '_')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ if (db.names.back().second.substr(0, 2) == " [")
+ db.names.back().second.erase(0, 1);
+ db.names.back().second.insert(0, " []");
+ first = t;
+ }
+ }
+ else if ('1' <= first[1] && first[1] <= '9')
+ {
+ const char* t = parse_number(first+1, last);
+ if (t != last && *t == '_')
+ {
+ const char* t2 = parse_type(t+1, last, db);
+ if (t2 != t+1)
+ {
+ if (db.names.empty())
+ return first;
+ if (db.names.back().second.substr(0, 2) == " [")
+ db.names.back().second.erase(0, 1);
+ db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]");
+ first = t2;
+ }
+ }
+ }
+ else
+ {
+ const char* t = parse_expression(first+1, last, db);
+ if (t != first+1 && t != last && *t == '_')
+ {
+ const char* t2 = parse_type(++t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto type = std::move(db.names.back());
+ db.names.pop_back();
+ auto expr = std::move(db.names.back());
+ db.names.back().first = std::move(type.first);
+ if (type.second.substr(0, 2) == " [")
+ type.second.erase(0, 1);
+ db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second);
+ first = t2;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
+// ::= DT <expression> E # decltype of an expression (C++0x)
+
+template <class C>
+const char*
+parse_decltype(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && first[0] == 'D')
+ {
+ switch (first[1])
+ {
+ case 't':
+ case 'T':
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "decltype(" + db.names.back().move_full() + ")";
+ first = t+1;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// extension:
+// <vector-type> ::= Dv <positive dimension number> _
+// <extended element type>
+// ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+// ::= p # AltiVec vector pixel
+
+template <class C>
+const char*
+parse_vector_type(const char* first, const char* last, C& db)
+{
+ if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
+ {
+ if ('1' <= first[2] && first[2] <= '9')
+ {
+ const char* t = parse_number(first+2, last);
+ if (t == last || *t != '_')
+ return first;
+ const char* num = first + 2;
+ size_t sz = static_cast<size_t>(t - num);
+ if (++t != last)
+ {
+ if (*t != 'p')
+ {
+ const char* t1 = parse_type(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " vector[" + typename C::String(num, sz) + "]";
+ first = t1;
+ }
+ }
+ else
+ {
+ ++t;
+ db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]");
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ typename C::String num;
+ const char* t1 = first+2;
+ if (*t1 != '_')
+ {
+ const char* t = parse_expression(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ num = db.names.back().move_full();
+ db.names.pop_back();
+ t1 = t;
+ }
+ }
+ if (t1 != last && *t1 == '_' && ++t1 != last)
+ {
+ const char* t = parse_type(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " vector[" + num + "]";
+ first = t;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// <type> ::= <builtin-type>
+// ::= <function-type>
+// ::= <class-enum-type>
+// ::= <array-type>
+// ::= <pointer-to-member-type>
+// ::= <template-param>
+// ::= <template-template-param> <template-args>
+// ::= <decltype>
+// ::= <substitution>
+// ::= <CV-qualifiers> <type>
+// ::= P <type> # pointer-to
+// ::= R <type> # reference-to
+// ::= O <type> # rvalue reference-to (C++0x)
+// ::= C <type> # complex pair (C 2000)
+// ::= G <type> # imaginary (C 2000)
+// ::= Dp <type> # pack expansion (C++0x)
+// ::= U <source-name> <type> # vendor extended type qualifier
+// extension := U <objc-name> <objc-type> # objc-type<identifier>
+// extension := <vector-type> # <vector-type> starts with Dv
+
+// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
+// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
+
+template <class C>
+const char*
+parse_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'r':
+ case 'V':
+ case 'K':
+ {
+ unsigned cv = 0;
+ const char* t = parse_cv_qualifiers(first, last, cv);
+ if (t != first)
+ {
+ bool is_function = *t == 'F';
+ size_t k0 = db.names.size();
+ const char* t1 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t1 != t)
+ {
+ if (is_function)
+ db.subs.pop_back();
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (is_function)
+ {
+ size_t p = db.names[k].second.size();
+ if (db.names[k].second[p-2] == '&')
+ p -= 3;
+ else if (db.names[k].second.back() == '&')
+ p -= 2;
+ if (cv & 1)
+ {
+ db.names[k].second.insert(p, " const");
+ p += 6;
+ }
+ if (cv & 2)
+ {
+ db.names[k].second.insert(p, " volatile");
+ p += 9;
+ }
+ if (cv & 4)
+ db.names[k].second.insert(p, " restrict");
+ }
+ else
+ {
+ if (cv & 1)
+ db.names[k].first.append(" const");
+ if (cv & 2)
+ db.names[k].first.append(" volatile");
+ if (cv & 4)
+ db.names[k].first.append(" restrict");
+ }
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t1;
+ }
+ }
+ }
+ break;
+ default:
+ {
+ const char* t = parse_builtin_type(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ }
+ else
+ {
+ switch (*first)
+ {
+ case 'A':
+ t = parse_array_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'C':
+ t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(" complex");
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'F':
+ t = parse_function_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'G':
+ t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(" imaginary");
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'M':
+ t = parse_pointer_to_member_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'O':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (!db.names[k].second.empty() &&
+ db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ db.names[k].first.append("&&");
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'P':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (!db.names[k].second.empty() &&
+ db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<")
+ {
+ db.names[k].first.append("*");
+ }
+ else
+ {
+ db.names[k].first.replace(0, 11, "id");
+ }
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'R':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (!db.names[k].second.empty() &&
+ db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ db.names[k].first.append("&");
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'T':
+ {
+ size_t k0 = db.names.size();
+ t = parse_template_param(first, last, db);
+ size_t k1 = db.names.size();
+ if (t != first)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.subs.back().push_back(db.names[k]);
+ if (db.try_to_parse_template_args && k1 == k0+1)
+ {
+ const char* t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t = t1;
+ }
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'U':
+ if (first+1 != last)
+ {
+ t = parse_source_name(first+1, last, db);
+ if (t != first+1)
+ {
+ const char* t2 = parse_type(t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto type = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.back().first.substr(0, 9) != "objcproto")
+ {
+ db.names.back() = type + " " + db.names.back().move_full();
+ }
+ else
+ {
+ auto proto = db.names.back().move_full();
+ db.names.pop_back();
+ t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db);
+ if (t != proto.data() + 9)
+ {
+ db.names.back() = type + "<" + db.names.back().move_full() + ">";
+ }
+ else
+ {
+ db.names.push_back(type + " " + proto);
+ }
+ }
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t2;
+ }
+ }
+ }
+ break;
+ case 'S':
+ if (first+1 != last && first[1] == 't')
+ {
+ t = parse_name(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ else
+ {
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ // Parsed a substitution. If the substitution is a
+ // <template-param> it might be followed by <template-args>.
+ t = parse_template_args(first, last, db);
+ if (t != first)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto template_args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += template_args;
+ // Need to create substitution for <template-template-param> <template-args>
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ }
+ break;
+ case 'D':
+ if (first+1 != last)
+ {
+ switch (first[1])
+ {
+ case 'p':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+2, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+2)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.subs.back().push_back(db.names[k]);
+ first = t;
+ return first;
+ }
+ break;
+ }
+ case 't':
+ case 'T':
+ t = parse_decltype(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ return first;
+ }
+ break;
+ case 'v':
+ t = parse_vector_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ return first;
+ }
+ break;
+ }
+ }
+ // drop through
+ default:
+ // must check for builtin-types before class-enum-types to avoid
+ // ambiguities with operator-names
+ t = parse_builtin_type(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ }
+ else
+ {
+ t = parse_name(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <operator-name>
+// ::= aa # &&
+// ::= ad # & (unary)
+// ::= an # &
+// ::= aN # &=
+// ::= aS # =
+// ::= cl # ()
+// ::= cm # ,
+// ::= co # ~
+// ::= cv <type> # (cast)
+// ::= da # delete[]
+// ::= de # * (unary)
+// ::= dl # delete
+// ::= dv # /
+// ::= dV # /=
+// ::= eo # ^
+// ::= eO # ^=
+// ::= eq # ==
+// ::= ge # >=
+// ::= gt # >
+// ::= ix # []
+// ::= le # <=
+// ::= li <source-name> # operator ""
+// ::= ls # <<
+// ::= lS # <<=
+// ::= lt # <
+// ::= mi # -
+// ::= mI # -=
+// ::= ml # *
+// ::= mL # *=
+// ::= mm # -- (postfix in <expression> context)
+// ::= na # new[]
+// ::= ne # !=
+// ::= ng # - (unary)
+// ::= nt # !
+// ::= nw # new
+// ::= oo # ||
+// ::= or # |
+// ::= oR # |=
+// ::= pm # ->*
+// ::= pl # +
+// ::= pL # +=
+// ::= pp # ++ (postfix in <expression> context)
+// ::= ps # + (unary)
+// ::= pt # ->
+// ::= qu # ?
+// ::= rm # %
+// ::= rM # %=
+// ::= rs # >>
+// ::= rS # >>=
+// ::= v <digit> <source-name> # vendor extended operator
+
+template <class C>
+const char*
+parse_operator_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ switch (first[0])
+ {
+ case 'a':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator&&");
+ first += 2;
+ break;
+ case 'd':
+ case 'n':
+ db.names.push_back("operator&");
+ first += 2;
+ break;
+ case 'N':
+ db.names.push_back("operator&=");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'c':
+ switch (first[1])
+ {
+ case 'l':
+ db.names.push_back("operator()");
+ first += 2;
+ break;
+ case 'm':
+ db.names.push_back("operator,");
+ first += 2;
+ break;
+ case 'o':
+ db.names.push_back("operator~");
+ first += 2;
+ break;
+ case 'v':
+ {
+ bool try_to_parse_template_args = db.try_to_parse_template_args;
+ db.try_to_parse_template_args = false;
+ const char* t = parse_type(first+2, last, db);
+ db.try_to_parse_template_args = try_to_parse_template_args;
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator ");
+ db.parsed_ctor_dtor_cv = true;
+ first = t;
+ }
+ }
+ break;
+ }
+ break;
+ case 'd':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator delete[]");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("operator*");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator delete");
+ first += 2;
+ break;
+ case 'v':
+ db.names.push_back("operator/");
+ first += 2;
+ break;
+ case 'V':
+ db.names.push_back("operator/=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'e':
+ switch (first[1])
+ {
+ case 'o':
+ db.names.push_back("operator^");
+ first += 2;
+ break;
+ case 'O':
+ db.names.push_back("operator^=");
+ first += 2;
+ break;
+ case 'q':
+ db.names.push_back("operator==");
+ first += 2;
+ break;
+ }
+ break;
+ case 'g':
+ switch (first[1])
+ {
+ case 'e':
+ db.names.push_back("operator>=");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator>");
+ first += 2;
+ break;
+ }
+ break;
+ case 'i':
+ if (first[1] == 'x')
+ {
+ db.names.push_back("operator[]");
+ first += 2;
+ }
+ break;
+ case 'l':
+ switch (first[1])
+ {
+ case 'e':
+ db.names.push_back("operator<=");
+ first += 2;
+ break;
+ case 'i':
+ {
+ const char* t = parse_source_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator\"\" ");
+ first = t;
+ }
+ }
+ break;
+ case 's':
+ db.names.push_back("operator<<");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator<<=");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator<");
+ first += 2;
+ break;
+ }
+ break;
+ case 'm':
+ switch (first[1])
+ {
+ case 'i':
+ db.names.push_back("operator-");
+ first += 2;
+ break;
+ case 'I':
+ db.names.push_back("operator-=");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator*");
+ first += 2;
+ break;
+ case 'L':
+ db.names.push_back("operator*=");
+ first += 2;
+ break;
+ case 'm':
+ db.names.push_back("operator--");
+ first += 2;
+ break;
+ }
+ break;
+ case 'n':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator new[]");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("operator!=");
+ first += 2;
+ break;
+ case 'g':
+ db.names.push_back("operator-");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator!");
+ first += 2;
+ break;
+ case 'w':
+ db.names.push_back("operator new");
+ first += 2;
+ break;
+ }
+ break;
+ case 'o':
+ switch (first[1])
+ {
+ case 'o':
+ db.names.push_back("operator||");
+ first += 2;
+ break;
+ case 'r':
+ db.names.push_back("operator|");
+ first += 2;
+ break;
+ case 'R':
+ db.names.push_back("operator|=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'p':
+ switch (first[1])
+ {
+ case 'm':
+ db.names.push_back("operator->*");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator+");
+ first += 2;
+ break;
+ case 'L':
+ db.names.push_back("operator+=");
+ first += 2;
+ break;
+ case 'p':
+ db.names.push_back("operator++");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("operator+");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator->");
+ first += 2;
+ break;
+ }
+ break;
+ case 'q':
+ if (first[1] == 'u')
+ {
+ db.names.push_back("operator?");
+ first += 2;
+ }
+ break;
+ case 'r':
+ switch (first[1])
+ {
+ case 'm':
+ db.names.push_back("operator%");
+ first += 2;
+ break;
+ case 'M':
+ db.names.push_back("operator%=");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("operator>>");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator>>=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'v':
+ if (std::isdigit(first[1]))
+ {
+ const char* t = parse_source_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator ");
+ first = t;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db)
+{
+ const char* t = parse_number(first, last);
+ if (t != first && t != last && *t == 'E')
+ {
+ if (lit.size() > 3)
+ db.names.push_back("(" + lit + ")");
+ else
+ db.names.emplace_back();
+ if (*first == 'n')
+ {
+ db.names.back().first += '-';
+ ++first;
+ }
+ db.names.back().first.append(first, t);
+ if (lit.size() <= 3)
+ db.names.back().first += lit;
+ first = t+1;
+ }
+ return first;
+}
+
+// <expr-primary> ::= L <type> <value number> E # integer literal
+// ::= L <type> <value float> E # floating literal
+// ::= L <string type> E # string literal
+// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
+// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
+// ::= L <mangled-name> E # external name
+
+template <class C>
+const char*
+parse_expr_primary(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && *first == 'L')
+ {
+ switch (first[1])
+ {
+ case 'w':
+ {
+ const char* t = parse_integer_literal(first+2, last, "wchar_t", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'b':
+ if (first[3] == 'E')
+ {
+ switch (first[2])
+ {
+ case '0':
+ db.names.push_back("false");
+ first += 4;
+ break;
+ case '1':
+ db.names.push_back("true");
+ first += 4;
+ break;
+ }
+ }
+ break;
+ case 'c':
+ {
+ const char* t = parse_integer_literal(first+2, last, "char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'a':
+ {
+ const char* t = parse_integer_literal(first+2, last, "signed char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'h':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 's':
+ {
+ const char* t = parse_integer_literal(first+2, last, "short", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 't':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned short", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'i':
+ {
+ const char* t = parse_integer_literal(first+2, last, "", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'j':
+ {
+ const char* t = parse_integer_literal(first+2, last, "u", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'l':
+ {
+ const char* t = parse_integer_literal(first+2, last, "l", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'm':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ul", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'x':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ll", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'y':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ull", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'n':
+ {
+ const char* t = parse_integer_literal(first+2, last, "__int128", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'o':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'f':
+ {
+ const char* t = parse_floating_number<float>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'd':
+ {
+ const char* t = parse_floating_number<double>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'e':
+ {
+ const char* t = parse_floating_number<long double>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case '_':
+ if (first[2] == 'Z')
+ {
+ const char* t = parse_encoding(first+3, last, db);
+ if (t != first+3 && t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ case 'T':
+ // Invalid mangled name per
+ // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+ break;
+ default:
+ {
+ // might be named type
+ const char* t = parse_type(first+1, last, db);
+ if (t != first+1 && t != last)
+ {
+ if (*t != 'E')
+ {
+ const char* n = t;
+ for (; n != last && isdigit(*n); ++n)
+ ;
+ if (n != t && n != last && *n == 'E')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n);
+ first = n+1;
+ break;
+ }
+ }
+ else
+ {
+ first = t+1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return first;
+}
+
+template <class String>
+String
+base_name(String& s)
+{
+ if (s.empty())
+ return s;
+ if (s == "std::string")
+ {
+ s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >";
+ return "basic_string";
+ }
+ if (s == "std::istream")
+ {
+ s = "std::basic_istream<char, std::char_traits<char> >";
+ return "basic_istream";
+ }
+ if (s == "std::ostream")
+ {
+ s = "std::basic_ostream<char, std::char_traits<char> >";
+ return "basic_ostream";
+ }
+ if (s == "std::iostream")
+ {
+ s = "std::basic_iostream<char, std::char_traits<char> >";
+ return "basic_iostream";
+ }
+ const char* const pf = s.data();
+ const char* pe = pf + s.size();
+ if (pe[-1] == '>')
+ {
+ unsigned c = 1;
+ while (true)
+ {
+ if (--pe == pf)
+ return String();
+ if (pe[-1] == '<')
+ {
+ if (--c == 0)
+ {
+ --pe;
+ break;
+ }
+ }
+ else if (pe[-1] == '>')
+ ++c;
+ }
+ }
+ const char* p0 = pe - 1;
+ for (; p0 != pf; --p0)
+ {
+ if (*p0 == ':')
+ {
+ ++p0;
+ break;
+ }
+ }
+ return String(p0, pe);
+}
+
+// <ctor-dtor-name> ::= C1 # complete object constructor
+// ::= C2 # base object constructor
+// ::= C3 # complete object allocating constructor
+// extension ::= C5 # ?
+// ::= D0 # deleting destructor
+// ::= D1 # complete object destructor
+// ::= D2 # base object destructor
+// extension ::= D5 # ?
+
+template <class C>
+const char*
+parse_ctor_dtor_name(const char* first, const char* last, C& db)
+{
+ if (last-first >= 2 && !db.names.empty())
+ {
+ switch (first[0])
+ {
+ case 'C':
+ switch (first[1])
+ {
+ case '1':
+ case '2':
+ case '3':
+ case '5':
+ if (db.names.empty())
+ return first;
+ db.names.push_back(base_name(db.names.back().first));
+ first += 2;
+ db.parsed_ctor_dtor_cv = true;
+ break;
+ }
+ break;
+ case 'D':
+ switch (first[1])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '5':
+ if (db.names.empty())
+ return first;
+ db.names.push_back("~" + base_name(db.names.back().first));
+ first += 2;
+ db.parsed_ctor_dtor_cv = true;
+ break;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
+// ::= <closure-type-name>
+//
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+//
+// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
+
+template <class C>
+const char*
+parse_unnamed_type_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2 && first[0] == 'U')
+ {
+ char type = first[1];
+ switch (type)
+ {
+ case 't':
+ {
+ db.names.push_back(typename C::String("'unnamed"));
+ const char* t0 = first+2;
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (std::isdigit(*t0))
+ {
+ const char* t1 = t0 + 1;
+ while (t1 != last && std::isdigit(*t1))
+ ++t1;
+ db.names.back().first.append(t0, t1);
+ t0 = t1;
+ }
+ db.names.back().first.push_back('\'');
+ if (t0 == last || *t0 != '_')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ first = t0 + 1;
+ }
+ break;
+ case 'l':
+ {
+ db.names.push_back(typename C::String("'lambda'("));
+ const char* t0 = first+2;
+ if (first[2] == 'v')
+ {
+ db.names.back().first += ')';
+ ++t0;
+ }
+ else
+ {
+ const char* t1 = parse_type(t0, last, db);
+ if (t1 == t0)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append(tmp);
+ t0 = t1;
+ while (true)
+ {
+ t1 = parse_type(t0, last, db);
+ if (t1 == t0)
+ break;
+ if (db.names.size() < 2)
+ return first;
+ tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ }
+ t0 = t1;
+ }
+ db.names.back().first.append(")");
+ }
+ if (t0 == last || *t0 != 'E')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ ++t0;
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (std::isdigit(*t0))
+ {
+ const char* t1 = t0 + 1;
+ while (t1 != last && std::isdigit(*t1))
+ ++t1;
+ db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1);
+ t0 = t1;
+ }
+ if (t0 == last || *t0 != '_')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ first = t0 + 1;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <unqualified-name> ::= <operator-name>
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <unnamed-type-name>
+
+template <class C>
+const char*
+parse_unqualified_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'C':
+ case 'D':
+ t = parse_ctor_dtor_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ case 'U':
+ t = parse_unnamed_type_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = parse_source_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ default:
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ };
+ }
+ return first;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name> # ::std::
+// extension ::= StL<unqualified-name>
+
+template <class C>
+const char*
+parse_unscoped_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ const char* t0 = first;
+ bool St = false;
+ if (first[0] == 'S' && first[1] == 't')
+ {
+ t0 += 2;
+ St = true;
+ if (t0 != last && *t0 == 'L')
+ ++t0;
+ }
+ const char* t1 = parse_unqualified_name(t0, last, db);
+ if (t1 != t0)
+ {
+ if (St)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "std::");
+ }
+ first = t1;
+ }
+ }
+ return first;
+}
+
+// at <type> # alignof (a type)
+
+template <class C>
+const char*
+parse_alignof_type(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// az <expression> # alignof (a expression)
+
+template <class C>
+const char*
+parse_alignof_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'a' && first[1] == 'z')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_noexcept_expression(const char* first, const char* last, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "noexcept (" + db.names.back().move_full() + ")";
+ first = t1;
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = op + "(" + db.names.back().move_full() + ")";
+ first = t1;
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ auto& nm = db.names.back().first;
+ nm.clear();
+ if (op == ">")
+ nm += '(';
+ nm += "(" + op1 + ") " + op + " (" + op2 + ")";
+ if (op == ">")
+ nm += ')';
+ first = t2;
+ }
+ else
+ db.names.pop_back();
+ }
+ return first;
+}
+
+// <expression> ::= <unary operator-name> <expression>
+// ::= <binary operator-name> <expression> <expression>
+// ::= <ternary operator-name> <expression> <expression> <expression>
+// ::= cl <expression>+ E # call
+// ::= cv <type> <expression> # conversion with one argument
+// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
+// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
+// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
+// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+// ::= [gs] dl <expression> # delete expression
+// ::= [gs] da <expression> # delete[] expression
+// ::= pp_ <expression> # prefix ++
+// ::= mm_ <expression> # prefix --
+// ::= ti <type> # typeid (type)
+// ::= te <expression> # typeid (expression)
+// ::= dc <type> <expression> # dynamic_cast<type> (expression)
+// ::= sc <type> <expression> # static_cast<type> (expression)
+// ::= cc <type> <expression> # const_cast<type> (expression)
+// ::= rc <type> <expression> # reinterpret_cast<type> (expression)
+// ::= st <type> # sizeof (a type)
+// ::= sz <expression> # sizeof (an expression)
+// ::= at <type> # alignof (a type)
+// ::= az <expression> # alignof (an expression)
+// ::= nx <expression> # noexcept (expression)
+// ::= <template-param>
+// ::= <function-param>
+// ::= dt <expression> <unresolved-name> # expr.name
+// ::= pt <expression> <unresolved-name> # expr->name
+// ::= ds <expression> <expression> # expr.*expr
+// ::= sZ <template-param> # size of a parameter pack
+// ::= sZ <function-param> # size of a function parameter pack
+// ::= sp <expression> # pack expansion
+// ::= tw <expression> # throw expression
+// ::= tr # throw with no operand (rethrow)
+// ::= <unresolved-name> # f(p), N::f(p), ::f(p),
+// # freestanding dependent name (e.g., T::x),
+// # objectless nonstatic member reference
+// ::= <expr-primary>
+
+template <class C>
+const char*
+parse_expression(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ const char* t = first;
+ bool parsed_gs = false;
+ if (last - first >= 4 && t[0] == 'g' && t[1] == 's')
+ {
+ t += 2;
+ parsed_gs = true;
+ }
+ switch (*t)
+ {
+ case 'L':
+ first = parse_expr_primary(first, last, db);
+ break;
+ case 'T':
+ first = parse_template_param(first, last, db);
+ break;
+ case 'f':
+ first = parse_function_param(first, last, db);
+ break;
+ case 'a':
+ switch (t[1])
+ {
+ case 'a':
+ t = parse_binary_expression(first+2, last, "&&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'd':
+ t = parse_prefix_expression(first+2, last, "&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'n':
+ t = parse_binary_expression(first+2, last, "&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'N':
+ t = parse_binary_expression(first+2, last, "&=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, "=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ first = parse_alignof_type(first, last, db);
+ break;
+ case 'z':
+ first = parse_alignof_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'c':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_const_cast_expr(first, last, db);
+ break;
+ case 'l':
+ first = parse_call_expr(first, last, db);
+ break;
+ case 'm':
+ t = parse_binary_expression(first+2, last, ",", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'o':
+ t = parse_prefix_expression(first+2, last, "~", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'v':
+ first = parse_conversion_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'd':
+ switch (t[1])
+ {
+ case 'a':
+ {
+ const char* t1 = parse_expression(t+2, last, db);
+ if (t1 != t+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+ "delete[] " + db.names.back().move_full();
+ first = t1;
+ }
+ }
+ break;
+ case 'c':
+ first = parse_dynamic_cast_expr(first, last, db);
+ break;
+ case 'e':
+ t = parse_prefix_expression(first+2, last, "*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ {
+ const char* t1 = parse_expression(t+2, last, db);
+ if (t1 != t+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+ "delete " + db.names.back().move_full();
+ first = t1;
+ }
+ }
+ break;
+ case 'n':
+ return parse_unresolved_name(first, last, db);
+ case 's':
+ first = parse_dot_star_expr(first, last, db);
+ break;
+ case 't':
+ first = parse_dot_expr(first, last, db);
+ break;
+ case 'v':
+ t = parse_binary_expression(first+2, last, "/", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'V':
+ t = parse_binary_expression(first+2, last, "/=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'e':
+ switch (t[1])
+ {
+ case 'o':
+ t = parse_binary_expression(first+2, last, "^", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'O':
+ t = parse_binary_expression(first+2, last, "^=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'q':
+ t = parse_binary_expression(first+2, last, "==", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'g':
+ switch (t[1])
+ {
+ case 'e':
+ t = parse_binary_expression(first+2, last, ">=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_binary_expression(first+2, last, ">", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'i':
+ if (t[1] == 'x')
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ db.names.back() = "(" + op1 + ")[" + op2 + "]";
+ first = t2;
+ }
+ else
+ db.names.pop_back();
+ }
+ }
+ break;
+ case 'l':
+ switch (t[1])
+ {
+ case 'e':
+ t = parse_binary_expression(first+2, last, "<=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 's':
+ t = parse_binary_expression(first+2, last, "<<", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, "<<=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_binary_expression(first+2, last, "<", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'm':
+ switch (t[1])
+ {
+ case 'i':
+ t = parse_binary_expression(first+2, last, "-", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'I':
+ t = parse_binary_expression(first+2, last, "-=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ t = parse_binary_expression(first+2, last, "*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'L':
+ t = parse_binary_expression(first+2, last, "*=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'm':
+ if (first+2 != last && first[2] == '_')
+ {
+ t = parse_prefix_expression(first+3, last, "--", db);
+ if (t != first+3)
+ first = t;
+ }
+ else
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")--";
+ first = t1;
+ }
+ }
+ break;
+ }
+ break;
+ case 'n':
+ switch (t[1])
+ {
+ case 'a':
+ case 'w':
+ first = parse_new_expr(first, last, db);
+ break;
+ case 'e':
+ t = parse_binary_expression(first+2, last, "!=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'g':
+ t = parse_prefix_expression(first+2, last, "-", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_prefix_expression(first+2, last, "!", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'x':
+ t = parse_noexcept_expression(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'o':
+ switch (t[1])
+ {
+ case 'n':
+ return parse_unresolved_name(first, last, db);
+ case 'o':
+ t = parse_binary_expression(first+2, last, "||", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'r':
+ t = parse_binary_expression(first+2, last, "|", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'R':
+ t = parse_binary_expression(first+2, last, "|=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'p':
+ switch (t[1])
+ {
+ case 'm':
+ t = parse_binary_expression(first+2, last, "->*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ t = parse_binary_expression(first+2, last, "+", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'L':
+ t = parse_binary_expression(first+2, last, "+=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'p':
+ if (first+2 != last && first[2] == '_')
+ {
+ t = parse_prefix_expression(first+3, last, "++", db);
+ if (t != first+3)
+ first = t;
+ }
+ else
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")++";
+ first = t1;
+ }
+ }
+ break;
+ case 's':
+ t = parse_prefix_expression(first+2, last, "+", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ first = parse_arrow_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'q':
+ if (t[1] == 'u')
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ const char* t3 = parse_expression(t2, last, db);
+ if (t3 != t2)
+ {
+ if (db.names.size() < 3)
+ return first;
+ auto op3 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")";
+ first = t3;
+ }
+ else
+ {
+ db.names.pop_back();
+ db.names.pop_back();
+ }
+ }
+ else
+ db.names.pop_back();
+ }
+ }
+ break;
+ case 'r':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_reinterpret_cast_expr(first, last, db);
+ break;
+ case 'm':
+ t = parse_binary_expression(first+2, last, "%", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'M':
+ t = parse_binary_expression(first+2, last, "%=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 's':
+ t = parse_binary_expression(first+2, last, ">>", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, ">>=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 's':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_static_cast_expr(first, last, db);
+ break;
+ case 'p':
+ first = parse_pack_expansion(first, last, db);
+ break;
+ case 'r':
+ return parse_unresolved_name(first, last, db);
+ case 't':
+ first = parse_sizeof_type_expr(first, last, db);
+ break;
+ case 'z':
+ first = parse_sizeof_expr_expr(first, last, db);
+ break;
+ case 'Z':
+ if (last - t >= 3)
+ {
+ switch (t[2])
+ {
+ case 'T':
+ first = parse_sizeof_param_pack_expr(first, last, db);
+ break;
+ case 'f':
+ first = parse_sizeof_function_param_pack_expr(first, last, db);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case 't':
+ switch (t[1])
+ {
+ case 'e':
+ case 'i':
+ first = parse_typeid_expr(first, last, db);
+ break;
+ case 'r':
+ db.names.push_back("throw");
+ first += 2;
+ break;
+ case 'w':
+ first = parse_throw_expr(first, last, db);
+ break;
+ }
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return parse_unresolved_name(first, last, db);
+ }
+ }
+ return first;
+}
+
+// <template-arg> ::= <type> # type or template
+// ::= X <expression> E # expression
+// ::= <expr-primary> # simple expressions
+// ::= J <template-arg>* E # argument pack
+// ::= LZ <encoding> E # extension
+
+template <class C>
+const char*
+parse_template_arg(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'X':
+ t = parse_expression(first+1, last, db);
+ if (t != first+1)
+ {
+ if (t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ case 'J':
+ t = first+1;
+ if (t == last)
+ return first;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_template_arg(t, last, db);
+ if (t1 == t)
+ return first;
+ t = t1;
+ }
+ first = t+1;
+ break;
+ case 'L':
+ // <expr-primary> or LZ <encoding> E
+ if (first+1 != last && first[1] == 'Z')
+ {
+ t = parse_encoding(first+2, last, db);
+ if (t != first+2 && t != last && *t == 'E')
+ first = t+1;
+ }
+ else
+ first = parse_expr_primary(first, last, db);
+ break;
+ default:
+ // <type>
+ first = parse_type(first, last, db);
+ break;
+ }
+ }
+ return first;
+}
+
+// <template-args> ::= I <template-arg>* E
+// extension, the abi says <template-arg>+
+
+template <class C>
+const char*
+parse_template_args(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2 && *first == 'I')
+ {
+ if (db.tag_templates)
+ db.template_param.back().clear();
+ const char* t = first+1;
+ typename C::String args("<");
+ while (*t != 'E')
+ {
+ if (db.tag_templates)
+ db.template_param.emplace_back(db.names.get_allocator());
+ size_t k0 = db.names.size();
+ const char* t1 = parse_template_arg(t, last, db);
+ size_t k1 = db.names.size();
+ if (db.tag_templates)
+ db.template_param.pop_back();
+ if (t1 == t || t1 == last)
+ return first;
+ if (db.tag_templates)
+ {
+ db.template_param.back().emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.template_param.back().back().push_back(db.names[k]);
+ }
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (args.size() > 1)
+ args += ", ";
+ args += db.names[k].move_full();
+ }
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ t = t1;
+ }
+ first = t + 1;
+ if (args.back() != '>')
+ args += ">";
+ else
+ args += " >";
+ db.names.push_back(std::move(args));
+
+ }
+ return first;
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+//
+// <prefix> ::= <prefix> <unqualified-name>
+// ::= <template-prefix> <template-args>
+// ::= <template-param>
+// ::= <decltype>
+// ::= # empty
+// ::= <substitution>
+// ::= <prefix> <data-member-prefix>
+// extension ::= L
+//
+// <template-prefix> ::= <prefix> <template unqualified-name>
+// ::= <template-param>
+// ::= <substitution>
+
+template <class C>
+const char*
+parse_nested_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (first != last && *first == 'N')
+ {
+ unsigned cv;
+ const char* t0 = parse_cv_qualifiers(first+1, last, cv);
+ if (t0 == last)
+ return first;
+ db.ref = 0;
+ if (*t0 == 'R')
+ {
+ db.ref = 1;
+ ++t0;
+ }
+ else if (*t0 == 'O')
+ {
+ db.ref = 2;
+ ++t0;
+ }
+ db.names.emplace_back();
+ if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
+ {
+ t0 += 2;
+ db.names.back().first = "std";
+ }
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ bool pop_subs = false;
+ bool component_ends_with_template_args = false;
+ while (*t0 != 'E')
+ {
+ component_ends_with_template_args = false;
+ const char* t1;
+ switch (*t0)
+ {
+ case 'S':
+ if (t0 + 1 != last && t0[1] == 't')
+ goto do_parse_unqualified_name;
+ t1 = parse_substitution(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ {
+ db.names.back().first += "::" + name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ else
+ db.names.back().first = name;
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'T':
+ t1 = parse_template_param(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'D':
+ if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
+ goto do_parse_unqualified_name;
+ t1 = parse_decltype(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'I':
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t0 = t1;
+ component_ends_with_template_args = true;
+ }
+ else
+ return first;
+ break;
+ case 'L':
+ if (++t0 == last)
+ return first;
+ break;
+ default:
+ do_parse_unqualified_name:
+ t1 = parse_unqualified_name(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ }
+ }
+ first = t0 + 1;
+ db.cv = cv;
+ if (pop_subs && !db.subs.empty())
+ db.subs.pop_back();
+ if (ends_with_template_args)
+ *ends_with_template_args = component_ends_with_template_args;
+ }
+ return first;
+}
+
+// <discriminator> := _ <non-negative number> # when number < 10
+// := __ <non-negative number> _ # when number >= 10
+// extension := decimal-digit+
+
+const char*
+parse_discriminator(const char* first, const char* last)
+{
+ // parse but ignore discriminator
+ if (first != last)
+ {
+ if (*first == '_')
+ {
+ const char* t1 = first+1;
+ if (t1 != last)
+ {
+ if (std::isdigit(*t1))
+ first = t1+1;
+ else if (*t1 == '_')
+ {
+ for (++t1; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ if (t1 != last && *t1 == '_')
+ first = t1 + 1;
+ }
+ }
+ }
+ else if (std::isdigit(*first))
+ {
+ const char* t1 = first+1;
+ for (; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ first = t1;
+ }
+ }
+ return first;
+}
+
+// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+// := Z <function encoding> E s [<discriminator>]
+// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+
+template <class C>
+const char*
+parse_local_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (first != last && *first == 'Z')
+ {
+ const char* t = parse_encoding(first+1, last, db);
+ if (t != first+1 && t != last && *t == 'E' && ++t != last)
+ {
+ switch (*t)
+ {
+ case 's':
+ first = parse_discriminator(t+1, last);
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append("::string literal");
+ break;
+ case 'd':
+ if (++t != last)
+ {
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ t = t1 + 1;
+ t1 = parse_name(t, last, db,
+ ends_with_template_args);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append("::");
+ db.names.back().first.append(name);
+ first = t1;
+ }
+ else
+ db.names.pop_back();
+ }
+ }
+ break;
+ default:
+ {
+ const char* t1 = parse_name(t, last, db,
+ ends_with_template_args);
+ if (t1 != t)
+ {
+ // parse but ignore discriminator
+ first = parse_discriminator(t1, last);
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append("::");
+ db.names.back().first.append(name);
+ }
+ else
+ db.names.pop_back();
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <name> ::= <nested-name> // N
+// ::= <local-name> # See Scope Encoding below // Z
+// ::= <unscoped-template-name> <template-args>
+// ::= <unscoped-name>
+
+// <unscoped-template-name> ::= <unscoped-name>
+// ::= <substitution>
+
+template <class C>
+const char*
+parse_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (last - first >= 2)
+ {
+ const char* t0 = first;
+ // extension: ignore L here
+ if (*t0 == 'L')
+ ++t0;
+ switch (*t0)
+ {
+ case 'N':
+ {
+ const char* t1 = parse_nested_name(t0, last, db,
+ ends_with_template_args);
+ if (t1 != t0)
+ first = t1;
+ break;
+ }
+ case 'Z':
+ {
+ const char* t1 = parse_local_name(t0, last, db,
+ ends_with_template_args);
+ if (t1 != t0)
+ first = t1;
+ break;
+ }
+ default:
+ {
+ const char* t1 = parse_unscoped_name(t0, last, db);
+ if (t1 != t0)
+ {
+ if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args>
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t0 = t1;
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += tmp;
+ first = t1;
+ if (ends_with_template_args)
+ *ends_with_template_args = true;
+ }
+ }
+ else // <unscoped-name>
+ first = t1;
+ }
+ else
+ { // try <substitution> <template-args>
+ t1 = parse_substitution(t0, last, db);
+ if (t1 != t0 && t1 != last && *t1 == 'I')
+ {
+ t0 = t1;
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += tmp;
+ first = t1;
+ if (ends_with_template_args)
+ *ends_with_template_args = true;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <call-offset> ::= h <nv-offset> _
+// ::= v <v-offset> _
+//
+// <nv-offset> ::= <offset number>
+// # non-virtual base override
+//
+// <v-offset> ::= <offset number> _ <virtual offset number>
+// # virtual base override, with vcall offset
+
+const char*
+parse_call_offset(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'h':
+ {
+ const char* t = parse_number(first + 1, last);
+ if (t != first + 1 && t != last && *t == '_')
+ first = t + 1;
+ }
+ break;
+ case 'v':
+ {
+ const char* t = parse_number(first + 1, last);
+ if (t != first + 1 && t != last && *t == '_')
+ {
+ const char* t2 = parse_number(++t, last);
+ if (t2 != t && t2 != last && *t2 == '_')
+ first = t2 + 1;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <special-name> ::= TV <type> # virtual table
+// ::= TT <type> # VTT structure (construction vtable index)
+// ::= TI <type> # typeinfo structure
+// ::= TS <type> # typeinfo name (null-terminated byte string)
+// ::= Tc <call-offset> <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// # first call-offset is 'this' adjustment
+// # second call-offset is result adjustment
+// ::= T <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// ::= GV <object name> # Guard variable for one-time initialization
+// # No <type>
+// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+// extension ::= GR <object name> # reference temporary for object
+
+template <class C>
+const char*
+parse_special_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'T':
+ switch (first[1])
+ {
+ case 'V':
+ // TV <type> # virtual table
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "vtable for ");
+ first = t;
+ }
+ break;
+ case 'T':
+ // TT <type> # VTT structure (construction vtable index)
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "VTT for ");
+ first = t;
+ }
+ break;
+ case 'I':
+ // TI <type> # typeinfo structure
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "typeinfo for ");
+ first = t;
+ }
+ break;
+ case 'S':
+ // TS <type> # typeinfo name (null-terminated byte string)
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "typeinfo name for ");
+ first = t;
+ }
+ break;
+ case 'c':
+ // Tc <call-offset> <call-offset> <base encoding>
+ {
+ const char* t0 = parse_call_offset(first+2, last);
+ if (t0 == first+2)
+ break;
+ const char* t1 = parse_call_offset(t0, last);
+ if (t1 == t0)
+ break;
+ t = parse_encoding(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "covariant return thunk to ");
+ first = t;
+ }
+ }
+ break;
+ case 'C':
+ // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t0 = parse_number(t, last);
+ if (t0 != t && t0 != last && *t0 == '_')
+ {
+ const char* t1 = parse_type(++t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto left = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first = "construction vtable for " +
+ std::move(left) + "-in-" +
+ db.names.back().move_full();
+ first = t1;
+ }
+ }
+ }
+ break;
+ default:
+ // T <call-offset> <base encoding>
+ {
+ const char* t0 = parse_call_offset(first+1, last);
+ if (t0 == first+1)
+ break;
+ t = parse_encoding(t0, last, db);
+ if (t != t0)
+ {
+ if (db.names.empty())
+ return first;
+ if (first[2] == 'v')
+ {
+ db.names.back().first.insert(0, "virtual thunk to ");
+ first = t;
+ }
+ else
+ {
+ db.names.back().first.insert(0, "non-virtual thunk to ");
+ first = t;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case 'G':
+ switch (first[1])
+ {
+ case 'V':
+ // GV <object name> # Guard variable for one-time initialization
+ t = parse_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "guard variable for ");
+ first = t;
+ }
+ break;
+ case 'R':
+ // extension ::= GR <object name> # reference temporary for object
+ t = parse_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "reference temporary for ");
+ first = t;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+template <class T>
+class save_value
+{
+ T& restore_;
+ T original_value_;
+public:
+ save_value(T& restore)
+ : restore_(restore),
+ original_value_(restore)
+ {}
+
+ ~save_value()
+ {
+ restore_ = std::move(original_value_);
+ }
+
+ save_value(const save_value&) = delete;
+ save_value& operator=(const save_value&) = delete;
+};
+
+// <encoding> ::= <function name> <bare-function-type>
+// ::= <data name>
+// ::= <special-name>
+
+template <class C>
+const char*
+parse_encoding(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
+ ++db.encoding_depth;
+ save_value<decltype(db.tag_templates)> sb(db.tag_templates);
+ if (db.encoding_depth > 1)
+ db.tag_templates = true;
+ switch (*first)
+ {
+ case 'G':
+ case 'T':
+ first = parse_special_name(first, last, db);
+ break;
+ default:
+ {
+ bool ends_with_template_args = false;
+ const char* t = parse_name(first, last, db,
+ &ends_with_template_args);
+ unsigned cv = db.cv;
+ unsigned ref = db.ref;
+ if (t != first)
+ {
+ if (t != last && *t != 'E' && *t != '.')
+ {
+ save_value<bool> sb2(db.tag_templates);
+ db.tag_templates = false;
+ const char* t2;
+ typename C::String ret2;
+ if (db.names.empty())
+ return first;
+ const typename C::String& nm = db.names.back().first;
+ if (nm.empty())
+ return first;
+ if (!db.parsed_ctor_dtor_cv && ends_with_template_args)
+ {
+ t2 = parse_type(t, last, db);
+ if (t2 == t)
+ return first;
+ if (db.names.size() < 2)
+ return first;
+ auto ret1 = std::move(db.names.back().first);
+ ret2 = std::move(db.names.back().second);
+ if (ret2.empty())
+ ret1 += ' ';
+ db.names.pop_back();
+ db.names.back().first.insert(0, ret1);
+ t = t2;
+ }
+ db.names.back().first += '(';
+ if (t != last && *t == 'v')
+ {
+ ++t;
+ }
+ else
+ {
+ bool first_arg = true;
+ while (true)
+ {
+ size_t k0 = db.names.size();
+ t2 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t2 == t)
+ break;
+ if (k1 > k0)
+ {
+ typename C::String tmp;
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (!tmp.empty())
+ tmp += ", ";
+ tmp += db.names[k].move_full();
+ }
+ for (size_t k = k0; k < k1; ++k)
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ if (!first_arg)
+ db.names.back().first += ", ";
+ else
+ first_arg = false;
+ db.names.back().first += tmp;
+ }
+ }
+ t = t2;
+ }
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first += ')';
+ if (cv & 1)
+ db.names.back().first.append(" const");
+ if (cv & 2)
+ db.names.back().first.append(" volatile");
+ if (cv & 4)
+ db.names.back().first.append(" restrict");
+ if (ref == 1)
+ db.names.back().first.append(" &");
+ else if (ref == 2)
+ db.names.back().first.append(" &&");
+ db.names.back().first += ret2;
+ first = t;
+ }
+ else
+ first = t;
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// _block_invoke
+// _block_invoke<decimal-digit>+
+// _block_invoke_<decimal-digit>+
+
+template <class C>
+const char*
+parse_block_invoke(const char* first, const char* last, C& db)
+{
+ if (last - first >= 13)
+ {
+ const char test[] = "_block_invoke";
+ const char* t = first;
+ for (int i = 0; i < 13; ++i, ++t)
+ {
+ if (*t != test[i])
+ return first;
+ }
+ if (t != last)
+ {
+ if (*t == '_')
+ {
+ // must have at least 1 decimal digit
+ if (++t == last || !std::isdigit(*t))
+ return first;
+ ++t;
+ }
+ // parse zero or more digits
+ while (t != last && isdigit(*t))
+ ++t;
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "invocation function for block in ");
+ first = t;
+ }
+ return first;
+}
+
+// extension
+// <dot-suffix> := .<anything and everything>
+
+template <class C>
+const char*
+parse_dot_suffix(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == '.')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " (" + typename C::String(first, last) + ")";
+ first = last;
+ }
+ return first;
+}
+
+// <block-involcaton-function> ___Z<encoding>_block_invoke
+// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
+// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
+// <mangled-name> ::= _Z<encoding>
+// ::= <type>
+
+template <class C>
+void
+demangle(const char* first, const char* last, C& db, int& status)
+{
+ if (first >= last)
+ {
+ status = invalid_mangled_name;
+ return;
+ }
+ if (*first == '_')
+ {
+ if (last - first >= 4)
+ {
+ if (first[1] == 'Z')
+ {
+ const char* t = parse_encoding(first+2, last, db);
+ if (t != first+2 && t != last && *t == '.')
+ t = parse_dot_suffix(t, last, db);
+ if (t != last)
+ status = invalid_mangled_name;
+ }
+ else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z')
+ {
+ const char* t = parse_encoding(first+4, last, db);
+ if (t != first+4 && t != last)
+ {
+ const char* t1 = parse_block_invoke(t, last, db);
+ if (t1 != last)
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ {
+ const char* t = parse_type(first, last, db);
+ if (t != last)
+ status = invalid_mangled_name;
+ }
+ if (status == success && db.names.empty())
+ status = invalid_mangled_name;
+}
+
+template <std::size_t N>
+class arena
+{
+ static const std::size_t alignment = 16;
+ LLVM_ALIGNAS(16) char buf_[N];
+ char* ptr_;
+
+ std::size_t
+ align_up(std::size_t n) LLVM_NOEXCEPT
+ {return (n + (alignment-1)) & ~(alignment-1);}
+
+ bool
+ pointer_in_buffer(char* p) LLVM_NOEXCEPT
+ {return buf_ <= p && p <= buf_ + N;}
+
+public:
+ arena() LLVM_NOEXCEPT : ptr_(buf_) {}
+ ~arena() {ptr_ = nullptr;}
+ arena(const arena&) = delete;
+ arena& operator=(const arena&) = delete;
+
+ char* allocate(std::size_t n);
+ void deallocate(char* p, std::size_t n) LLVM_NOEXCEPT;
+
+ static LLVM_CONSTEXPR std::size_t size() {return N;}
+ std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);}
+ void reset() {ptr_ = buf_;}
+};
+
+template <std::size_t N>
+char*
+arena<N>::allocate(std::size_t n)
+{
+ n = align_up(n);
+ if (static_cast<std::size_t>(buf_ + N - ptr_) >= n)
+ {
+ char* r = ptr_;
+ ptr_ += n;
+ return r;
+ }
+ return static_cast<char*>(std::malloc(n));
+}
+
+template <std::size_t N>
+void
+arena<N>::deallocate(char* p, std::size_t n) LLVM_NOEXCEPT
+{
+ if (pointer_in_buffer(p))
+ {
+ n = align_up(n);
+ if (p + n == ptr_)
+ ptr_ = p;
+ }
+ else
+ std::free(p);
+}
+
+template <class T, std::size_t N>
+class short_alloc
+{
+ arena<N>& a_;
+public:
+ typedef T value_type;
+
+public:
+ template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;};
+
+ short_alloc(arena<N>& a) LLVM_NOEXCEPT : a_(a) {}
+ template <class U>
+ short_alloc(const short_alloc<U, N>& a) LLVM_NOEXCEPT
+ : a_(a.a_) {}
+ short_alloc(const short_alloc&) = default;
+ short_alloc& operator=(const short_alloc&) = delete;
+
+ T* allocate(std::size_t n)
+ {
+ return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));
+ }
+ void deallocate(T* p, std::size_t n) LLVM_NOEXCEPT
+ {
+ a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
+ }
+
+ template <class T1, std::size_t N1, class U, std::size_t M>
+ friend
+ bool
+ operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) LLVM_NOEXCEPT;
+
+ template <class U, std::size_t M> friend class short_alloc;
+};
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) LLVM_NOEXCEPT
+{
+ return N == M && &x.a_ == &y.a_;
+}
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) LLVM_NOEXCEPT
+{
+ return !(x == y);
+}
+
+template <class T>
+class malloc_alloc
+{
+public:
+ typedef T value_type;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+
+ malloc_alloc() = default;
+ template <class U> malloc_alloc(const malloc_alloc<U>&) LLVM_NOEXCEPT {}
+
+ T* allocate(std::size_t n)
+ {
+ return static_cast<T*>(std::malloc(n*sizeof(T)));
+ }
+ void deallocate(T* p, std::size_t) LLVM_NOEXCEPT
+ {
+ std::free(p);
+ }
+ template<class Other>
+ struct rebind
+ {
+ typedef malloc_alloc<Other> other;
+ };
+ void construct(T *p)
+ {
+ ::new (p) T();
+ }
+ void construct(T *p, const T& t)
+ {
+ ::new (p) T(t);
+ }
+ void destroy(T *p)
+ {
+ p->~T();
+ }
+};
+
+template <class T, class U>
+inline
+bool
+operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) LLVM_NOEXCEPT
+{
+ return true;
+}
+
+template <class T, class U>
+inline
+bool
+operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) LLVM_NOEXCEPT
+{
+ return !(x == y);
+}
+
+const size_t bs = 4 * 1024;
+template <class T> using Alloc = short_alloc<T, bs>;
+template <class T> using Vector = std::vector<T, Alloc<T>>;
+
+template <class StrT>
+struct string_pair
+{
+ StrT first;
+ StrT second;
+
+ string_pair() = default;
+ string_pair(StrT f) : first(std::move(f)) {}
+ string_pair(StrT f, StrT s)
+ : first(std::move(f)), second(std::move(s)) {}
+ template <size_t N>
+ string_pair(const char (&s)[N]) : first(s, N-1) {}
+
+ size_t size() const {return first.size() + second.size();}
+ StrT full() const {return first + second;}
+ StrT move_full() {return std::move(first) + std::move(second);}
+};
+
+struct Db
+{
+ typedef std::basic_string<char, std::char_traits<char>,
+ malloc_alloc<char>> String;
+ typedef Vector<string_pair<String>> sub_type;
+ typedef Vector<sub_type> template_param_type;
+ sub_type names;
+ template_param_type subs;
+ Vector<template_param_type> template_param;
+ unsigned cv;
+ unsigned ref;
+ unsigned encoding_depth;
+ bool parsed_ctor_dtor_cv;
+ bool tag_templates;
+ bool fix_forward_references;
+ bool try_to_parse_template_args;
+
+ template <size_t N>
+ Db(arena<N>& ar) :
+ names(ar),
+ subs(0, names, ar),
+ template_param(0, subs, ar)
+ {}
+};
+
+} // unnamed namespace
+
+char*
+__cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
+{
+ if (mangled_name == nullptr || (buf != nullptr && n == nullptr))
+ {
+ if (status)
+ *status = invalid_args;
+ return nullptr;
+ }
+ size_t internal_size = buf != nullptr ? *n : 0;
+ arena<bs> a;
+ Db db(a);
+ db.cv = 0;
+ db.ref = 0;
+ db.encoding_depth = 0;
+ db.parsed_ctor_dtor_cv = false;
+ db.tag_templates = true;
+ db.template_param.emplace_back(a);
+ db.fix_forward_references = false;
+ db.try_to_parse_template_args = true;
+ int internal_status = success;
+ size_t len = std::strlen(mangled_name);
+ demangle(mangled_name, mangled_name + len, db,
+ internal_status);
+ if (internal_status == success && db.fix_forward_references &&
+ !db.template_param.empty() && !db.template_param.front().empty())
+ {
+ db.fix_forward_references = false;
+ db.tag_templates = false;
+ db.names.clear();
+ db.subs.clear();
+ demangle(mangled_name, mangled_name + len, db, internal_status);
+ if (db.fix_forward_references)
+ internal_status = invalid_mangled_name;
+ }
+ if (internal_status == success)
+ {
+ size_t sz = db.names.back().size() + 1;
+ if (sz > internal_size)
+ {
+ char* newbuf = static_cast<char*>(std::realloc(buf, sz));
+ if (newbuf == nullptr)
+ {
+ internal_status = memory_alloc_failure;
+ buf = nullptr;
+ }
+ else
+ {
+ buf = newbuf;
+ if (n != nullptr)
+ *n = sz;
+ }
+ }
+ if (buf != nullptr)
+ {
+ db.names.back().first += db.names.back().second;
+ std::memcpy(buf, db.names.back().first.data(), sz-1);
+ buf[sz-1] = char(0);
+ }
+ }
+ else
+ buf = nullptr;
+ if (status)
+ *status = internal_status;
+ return buf;
+}
+
+} // lldb_private
diff --git a/source/Core/DataBufferHeap.cpp b/source/Core/DataBufferHeap.cpp
index 984b36e54153..ba1314448bbd 100644
--- a/source/Core/DataBufferHeap.cpp
+++ b/source/Core/DataBufferHeap.cpp
@@ -106,7 +106,7 @@ DataBufferHeap::CopyData (const void *src, uint64_t src_len)
void
DataBufferHeap::AppendData (const void *src, uint64_t src_len)
{
- m_data.insert(m_data.end(), (uint8_t *)src, (uint8_t *)src + src_len);
+ m_data.insert(m_data.end(), (const uint8_t *)src, (const uint8_t *)src + src_len);
}
void
diff --git a/source/Core/DataBufferMemoryMap.cpp b/source/Core/DataBufferMemoryMap.cpp
index 4ca43b89eef1..b3211b35af85 100644
--- a/source/Core/DataBufferMemoryMap.cpp
+++ b/source/Core/DataBufferMemoryMap.cpp
@@ -26,7 +26,6 @@
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Core/Log.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
@@ -91,7 +90,8 @@ DataBufferMemoryMap::Clear()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
if (log)
- log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %" PRIu64 "", m_mmap_addr, (uint64_t)m_mmap_size);
+ log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %" PRIu64 "", (void *)m_mmap_addr,
+ (uint64_t)m_mmap_size);
#ifdef _WIN32
UnmapViewOfFile(m_mmap_addr);
#else
@@ -284,9 +284,9 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
// Save the actual mmap'ed size
m_mmap_size = length + page_offset;
- // Our data is at an offset into the the mapped data
+ // Our data is at an offset into the mapped data
m_data = m_mmap_addr + page_offset;
- // Our pretend size is the size that was requestd
+ // Our pretend size is the size that was requested
m_size = length;
}
}
@@ -307,8 +307,10 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
if (log)
{
- log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %" PRIu64 ", error = %s",
- m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString());
+ log->Printf(
+ "DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %" PRIu64
+ ", error = %s",
+ (void *)m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString());
}
}
}
diff --git a/source/Core/DataEncoder.cpp b/source/Core/DataEncoder.cpp
index 92a9104acc3a..d21ca423892f 100644
--- a/source/Core/DataEncoder.cpp
+++ b/source/Core/DataEncoder.cpp
@@ -21,36 +21,36 @@ using namespace lldb;
using namespace lldb_private;
static inline void
-WriteInt16(const unsigned char* ptr, unsigned offset, uint16_t value)
+WriteInt16(unsigned char* ptr, unsigned offset, uint16_t value)
{
*(uint16_t *)(ptr + offset) = value;
}
static inline void
-WriteInt32 (const unsigned char* ptr, unsigned offset, uint32_t value)
+WriteInt32 (unsigned char* ptr, unsigned offset, uint32_t value)
{
*(uint32_t *)(ptr + offset) = value;
}
static inline void
-WriteInt64(const unsigned char* ptr, unsigned offset, uint64_t value)
+WriteInt64(unsigned char* ptr, unsigned offset, uint64_t value)
{
*(uint64_t *)(ptr + offset) = value;
}
static inline void
-WriteSwappedInt16(const unsigned char* ptr, unsigned offset, uint16_t value)
+WriteSwappedInt16(unsigned char* ptr, unsigned offset, uint16_t value)
{
*(uint16_t *)(ptr + offset) = llvm::ByteSwap_16(value);
}
static inline void
-WriteSwappedInt32 (const unsigned char* ptr, unsigned offset, uint32_t value)
+WriteSwappedInt32 (unsigned char* ptr, unsigned offset, uint32_t value)
{
*(uint32_t *)(ptr + offset) = llvm::ByteSwap_32(value);
}
static inline void
-WriteSwappedInt64(const unsigned char* ptr, unsigned offset, uint64_t value)
+WriteSwappedInt64(unsigned char* ptr, unsigned offset, uint64_t value)
{
*(uint64_t *)(ptr + offset) = llvm::ByteSwap_64(value);
}
@@ -153,7 +153,7 @@ DataEncoder::GetSharedDataOffset () const
// any data extracted will be endian swapped.
//----------------------------------------------------------------------
uint32_t
-DataEncoder::SetData (const void *bytes, uint32_t length, ByteOrder endian)
+DataEncoder::SetData (void *bytes, uint32_t length, ByteOrder endian)
{
m_byte_order = endian;
m_data_sp.reset();
diff --git a/source/Core/DataExtractor.cpp b/source/Core/DataExtractor.cpp
index 6e1d63095cf3..b4b43ed97780 100644
--- a/source/Core/DataExtractor.cpp
+++ b/source/Core/DataExtractor.cpp
@@ -1710,7 +1710,7 @@ DataExtractor::Dump (Stream *s,
{
size_t complex_int_byte_size = item_byte_size / 2;
- if (complex_int_byte_size <= 8)
+ if (complex_int_byte_size > 0 && complex_int_byte_size <= 8)
{
s->Printf("%" PRIu64, GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
s->Printf(" + %" PRIu64 "i", GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
index f25a3f41825f..cd41e5d65103 100644
--- a/source/Core/Debugger.cpp
+++ b/source/Core/Debugger.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/Debugger.h"
#include <map>
@@ -39,6 +37,7 @@
#include "lldb/Host/Terminal.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/OptionValueSInt64.h"
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Symbol/ClangASTContext.h"
@@ -63,7 +62,6 @@ using namespace lldb;
using namespace lldb_private;
-static uint32_t g_shared_debugger_refcount = 0;
static lldb::user_id_t g_unique_id = 1;
static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024;
@@ -126,7 +124,21 @@ g_language_enumerators[] =
FILE_AND_LINE\
"\\n"
-#define DEFAULT_DISASSEMBLY_FORMAT "${current-pc-arrow}${addr-file-or-load}{ <${function.name-without-args}${function.concrete-only-addr-offset-no-padding}>}: "
+// Three parts to this disassembly format specification:
+// 1. If this is a new function/symbol (no previous symbol/function), print
+// dylib`funcname:\n
+// 2. If this is a symbol context change (different from previous symbol/function), print
+// dylib`funcname:\n
+// 3. print
+// address <+offset>:
+#define DEFAULT_DISASSEMBLY_FORMAT "{${function.initial-function}{${module.file.basename}`}{${function.name-without-args}}:\n}{${function.changed}\n{${module.file.basename}`}{${function.name-without-args}}:\n}{${current-pc-arrow} }${addr-file-or-load}{ <${function.concrete-only-addr-offset-no-padding}>}: "
+
+// gdb's disassembly format can be emulated with
+// ${current-pc-arrow}${addr-file-or-load}{ <${function.name-without-args}${function.concrete-only-addr-offset-no-padding}>}:
+
+// lldb's original format for disassembly would look like this format string -
+// {${function.initial-function}{${module.file.basename}`}{${function.name-without-args}}:\n}{${function.changed}\n{${module.file.basename}`}{${function.name-without-args}}:\n}{${current-pc-arrow} }{${addr-file-or-load}}:
+
static PropertyDefinition
g_properties[] =
@@ -170,7 +182,7 @@ enum
ePropertyEscapeNonPrintables
};
-Debugger::LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL;
+LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL;
Error
Debugger::SetPropertyValue (const ExecutionContext *exe_ctx,
@@ -391,36 +403,24 @@ Debugger::GetEscapeNonPrintables () const
//}
//
-int
-Debugger::TestDebuggerRefCount ()
-{
- return g_shared_debugger_refcount;
-}
-
+static bool lldb_initialized = false;
void
-Debugger::Initialize (LoadPluginCallbackType load_plugin_callback)
+Debugger::Initialize(LoadPluginCallbackType load_plugin_callback)
{
+ assert(!lldb_initialized && "Debugger::Initialize called more than once!");
+
+ lldb_initialized = true;
g_load_plugin_callback = load_plugin_callback;
- if (g_shared_debugger_refcount++ == 0)
- lldb_private::Initialize();
}
void
Debugger::Terminate ()
{
- if (g_shared_debugger_refcount > 0)
- {
- g_shared_debugger_refcount--;
- if (g_shared_debugger_refcount == 0)
- {
- lldb_private::WillTerminate();
- lldb_private::Terminate();
+ assert(lldb_initialized && "Debugger::Terminate called without a matching Debugger::Initialize!");
- // Clear our master list of debugger objects
- Mutex::Locker locker (GetDebuggerListMutex ());
- GetDebuggerList().clear();
- }
- }
+ // Clear our master list of debugger objects
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ GetDebuggerList().clear();
}
void
@@ -553,7 +553,7 @@ DebuggerSP
Debugger::CreateInstance (lldb::LogOutputCallback log_callback, void *baton)
{
DebuggerSP debugger_sp (new Debugger(log_callback, baton));
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
GetDebuggerList().push_back(debugger_sp);
@@ -570,7 +570,7 @@ Debugger::Destroy (DebuggerSP &debugger_sp)
debugger_sp->Clear();
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList ();
@@ -590,7 +590,7 @@ DebuggerSP
Debugger::FindDebuggerWithInstanceName (const ConstString &instance_name)
{
DebuggerSP debugger_sp;
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList();
@@ -612,7 +612,7 @@ TargetSP
Debugger::FindTargetWithProcessID (lldb::pid_t pid)
{
TargetSP target_sp;
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList();
@@ -631,7 +631,7 @@ TargetSP
Debugger::FindTargetWithProcess (Process *process)
{
TargetSP target_sp;
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList();
@@ -682,6 +682,10 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) :
ConstString("Settings specify to debugging targets."),
true,
Target::GetGlobalProperties()->GetValueProperties());
+ m_collection_sp->AppendProperty (ConstString("platform"),
+ ConstString("Platform settings."),
+ true,
+ Platform::GetGlobalPlatformProperties()->GetValueProperties());
if (m_command_interpreter_ap.get())
{
m_collection_sp->AppendProperty (ConstString("interpreter"),
@@ -879,34 +883,27 @@ Debugger::ClearIOHandlers ()
{
IOHandlerSP reader_sp (m_input_reader_stack.Top());
if (reader_sp)
- {
- m_input_reader_stack.Pop();
- reader_sp->SetIsDone(true);
- reader_sp->Cancel();
- }
+ PopIOHandler (reader_sp);
}
}
void
-Debugger::ExecuteIOHanders()
+Debugger::ExecuteIOHandlers()
{
-
while (1)
{
IOHandlerSP reader_sp(m_input_reader_stack.Top());
if (!reader_sp)
break;
- reader_sp->Activate();
reader_sp->Run();
- reader_sp->Deactivate();
// Remove all input readers that are done from the top of the stack
while (1)
{
IOHandlerSP top_reader_sp = m_input_reader_stack.Top();
if (top_reader_sp && top_reader_sp->GetIsDone())
- m_input_reader_stack.Pop();
+ PopIOHandler (top_reader_sp);
else
break;
}
@@ -920,6 +917,12 @@ Debugger::IsTopIOHandler (const lldb::IOHandlerSP& reader_sp)
return m_input_reader_stack.IsTop (reader_sp);
}
+void
+Debugger::PrintAsync (const char *s, size_t len, bool is_stdout)
+{
+ lldb::StreamFileSP stream = is_stdout ? GetOutputFile() : GetErrorFile();
+ m_input_reader_stack.PrintAsync(stream.get(), s, len);
+}
ConstString
Debugger::GetTopIOHandlerControlSequence(char ch)
@@ -943,25 +946,23 @@ void
Debugger::RunIOHandler (const IOHandlerSP& reader_sp)
{
PushIOHandler (reader_sp);
-
+
IOHandlerSP top_reader_sp = reader_sp;
while (top_reader_sp)
{
- top_reader_sp->Activate();
top_reader_sp->Run();
- top_reader_sp->Deactivate();
-
+
if (top_reader_sp.get() == reader_sp.get())
{
if (PopIOHandler (reader_sp))
break;
}
-
+
while (1)
{
top_reader_sp = m_input_reader_stack.Top();
if (top_reader_sp && top_reader_sp->GetIsDone())
- m_input_reader_stack.Pop();
+ PopIOHandler (top_reader_sp);
else
break;
}
@@ -1024,93 +1025,73 @@ Debugger::PushIOHandler (const IOHandlerSP& reader_sp)
if (!reader_sp)
return;
- // Got the current top input reader...
+ Mutex::Locker locker (m_input_reader_stack.GetMutex());
+
+ // Get the current top input reader...
IOHandlerSP top_reader_sp (m_input_reader_stack.Top());
// Don't push the same IO handler twice...
- if (reader_sp.get() != top_reader_sp.get())
- {
- // Push our new input reader
- m_input_reader_stack.Push (reader_sp);
+ if (reader_sp == top_reader_sp)
+ return;
- // Interrupt the top input reader to it will exit its Run() function
- // and let this new input reader take over
- if (top_reader_sp)
- top_reader_sp->Deactivate();
+ // Push our new input reader
+ m_input_reader_stack.Push (reader_sp);
+ reader_sp->Activate();
+
+ // Interrupt the top input reader to it will exit its Run() function
+ // and let this new input reader take over
+ if (top_reader_sp)
+ {
+ top_reader_sp->Deactivate();
+ top_reader_sp->Cancel();
}
}
bool
Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp)
{
- bool result = false;
-
+ if (! pop_reader_sp)
+ return false;
+
Mutex::Locker locker (m_input_reader_stack.GetMutex());
// The reader on the stop of the stack is done, so let the next
// read on the stack refresh its prompt and if there is one...
- if (!m_input_reader_stack.IsEmpty())
- {
- IOHandlerSP reader_sp(m_input_reader_stack.Top());
-
- if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get())
- {
- reader_sp->Deactivate();
- reader_sp->Cancel();
- m_input_reader_stack.Pop ();
-
- reader_sp = m_input_reader_stack.Top();
- if (reader_sp)
- reader_sp->Activate();
-
- result = true;
- }
- }
- return result;
-}
-
-bool
-Debugger::HideTopIOHandler()
-{
- Mutex::Locker locker;
-
- if (locker.TryLock(m_input_reader_stack.GetMutex()))
- {
- IOHandlerSP reader_sp(m_input_reader_stack.Top());
- if (reader_sp)
- reader_sp->Hide();
- return true;
- }
- return false;
-}
+ if (m_input_reader_stack.IsEmpty())
+ return false;
-void
-Debugger::RefreshTopIOHandler()
-{
IOHandlerSP reader_sp(m_input_reader_stack.Top());
+
+ if (pop_reader_sp != reader_sp)
+ return false;
+
+ reader_sp->Deactivate();
+ reader_sp->Cancel();
+ m_input_reader_stack.Pop ();
+
+ reader_sp = m_input_reader_stack.Top();
if (reader_sp)
- reader_sp->Refresh();
-}
+ reader_sp->Activate();
+ return true;
+}
StreamSP
Debugger::GetAsyncOutputStream ()
{
- return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
- CommandInterpreter::eBroadcastBitAsynchronousOutputData));
+ return StreamSP (new StreamAsynchronousIO (*this, true));
}
StreamSP
Debugger::GetAsyncErrorStream ()
{
- return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
- CommandInterpreter::eBroadcastBitAsynchronousErrorData));
+ return StreamSP (new StreamAsynchronousIO (*this, false));
}
size_t
Debugger::GetNumDebuggers()
{
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
return GetDebuggerList().size();
@@ -1123,7 +1104,7 @@ Debugger::GetDebuggerAtIndex (size_t index)
{
DebuggerSP debugger_sp;
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList();
@@ -1140,7 +1121,7 @@ Debugger::FindDebuggerWithID (lldb::user_id_t id)
{
DebuggerSP debugger_sp;
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList();
@@ -1292,8 +1273,6 @@ Debugger::SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton)
bool
Debugger::EnableLog (const char *channel, const char **categories, const char *log_file, uint32_t log_options, Stream &error_stream)
{
- Log::Callbacks log_callbacks;
-
StreamSP log_stream_sp;
if (m_log_callback_stream_sp)
{
@@ -1312,7 +1291,12 @@ Debugger::EnableLog (const char *channel, const char **categories, const char *l
log_stream_sp = pos->second.lock();
if (!log_stream_sp)
{
- log_stream_sp.reset (new StreamFile (log_file));
+ uint32_t options = File::eOpenOptionWrite | File::eOpenOptionCanCreate
+ | File::eOpenOptionCloseOnExec | File::eOpenOptionAppend;
+ if (! (log_options & LLDB_LOG_OPTION_APPEND))
+ options |= File::eOpenOptionTruncate;
+
+ log_stream_sp.reset (new StreamFile (log_file, options));
m_log_streams[log_file] = log_stream_sp;
}
}
@@ -1321,33 +1305,7 @@ Debugger::EnableLog (const char *channel, const char **categories, const char *l
if (log_options == 0)
log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE;
- if (Log::GetLogChannelCallbacks (ConstString(channel), log_callbacks))
- {
- log_callbacks.enable (log_stream_sp, log_options, categories, &error_stream);
- return true;
- }
- else
- {
- LogChannelSP log_channel_sp (LogChannel::FindPlugin (channel));
- if (log_channel_sp)
- {
- if (log_channel_sp->Enable (log_stream_sp, log_options, &error_stream, categories))
- {
- return true;
- }
- else
- {
- error_stream.Printf ("Invalid log channel '%s'.\n", channel);
- return false;
- }
- }
- else
- {
- error_stream.Printf ("Invalid log channel '%s'.\n", channel);
- return false;
- }
- }
- return false;
+ return Log::EnableLogChannel(log_stream_sp, log_options, channel, categories, error_stream);
}
SourceManager &
@@ -1385,14 +1343,14 @@ Debugger::HandleBreakpointEvent (const EventSP &event_sp)
if (num_new_locations > 0)
{
BreakpointSP breakpoint = Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp);
- StreamFileSP output_sp (GetOutputFile());
+ StreamSP output_sp (GetAsyncOutputStream());
if (output_sp)
{
output_sp->Printf("%d location%s added to breakpoint %d\n",
num_new_locations,
num_new_locations == 1 ? "" : "s",
breakpoint->GetID());
- RefreshTopIOHandler();
+ output_sp->Flush();
}
}
}
@@ -1479,8 +1437,8 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
const uint32_t event_type = event_sp->GetType();
ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
- StreamString output_stream;
- StreamString error_stream;
+ StreamSP output_stream_sp = GetAsyncOutputStream();
+ StreamSP error_stream_sp = GetAsyncErrorStream();
const bool gui_enabled = IsForwardingEvents();
if (!gui_enabled)
@@ -1488,47 +1446,43 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
bool pop_process_io_handler = false;
assert (process_sp);
- if (event_type & Process::eBroadcastBitSTDOUT || event_type & Process::eBroadcastBitStateChanged)
+ bool state_is_stopped = false;
+ const bool got_state_changed = (event_type & Process::eBroadcastBitStateChanged) != 0;
+ const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0;
+ const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0;
+ if (got_state_changed)
{
- GetProcessSTDOUT (process_sp.get(), &output_stream);
+ StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
+ state_is_stopped = StateIsStoppedState(event_state, false);
}
- if (event_type & Process::eBroadcastBitSTDERR || event_type & Process::eBroadcastBitStateChanged)
+ // Display running state changes first before any STDIO
+ if (got_state_changed && !state_is_stopped)
{
- GetProcessSTDERR (process_sp.get(), &error_stream);
+ Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler);
}
- if (event_type & Process::eBroadcastBitStateChanged)
+ // Now display and STDOUT
+ if (got_stdout || got_state_changed)
{
- Process::HandleProcessStateChangedEvent (event_sp, &output_stream, pop_process_io_handler);
+ GetProcessSTDOUT (process_sp.get(), output_stream_sp.get());
}
- if (output_stream.GetSize() || error_stream.GetSize())
+ // Now display and STDERR
+ if (got_stderr || got_state_changed)
{
- StreamFileSP error_stream_sp (GetOutputFile());
- bool top_io_handler_hid = false;
-
- if (process_sp->ProcessIOHandlerIsActive() == false)
- top_io_handler_hid = HideTopIOHandler();
-
- if (output_stream.GetSize())
- {
- StreamFileSP output_stream_sp (GetOutputFile());
- if (output_stream_sp)
- output_stream_sp->Write (output_stream.GetData(), output_stream.GetSize());
- }
-
- if (error_stream.GetSize())
- {
- StreamFileSP error_stream_sp (GetErrorFile());
- if (error_stream_sp)
- error_stream_sp->Write (error_stream.GetData(), error_stream.GetSize());
- }
+ GetProcessSTDERR (process_sp.get(), error_stream_sp.get());
+ }
- if (top_io_handler_hid)
- RefreshTopIOHandler();
+ // Now display any stopped state changes after any STDIO
+ if (got_state_changed && state_is_stopped)
+ {
+ Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler);
}
+ output_stream_sp->Flush();
+ error_stream_sp->Flush();
+
if (pop_process_io_handler)
process_sp->PopProcessIOHandler();
}
@@ -1547,10 +1501,7 @@ Debugger::HandleThreadEvent (const EventSP &event_sp)
ThreadSP thread_sp (Thread::ThreadEventData::GetThreadFromEvent (event_sp.get()));
if (thread_sp)
{
- HideTopIOHandler();
- StreamFileSP stream_sp (GetOutputFile());
- thread_sp->GetStatus(*stream_sp, 0, 1, 1);
- RefreshTopIOHandler();
+ thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1);
}
}
}
@@ -1644,13 +1595,11 @@ Debugger::DefaultEventHandler()
const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get()));
if (data && data[0])
{
- StreamFileSP error_sp (GetErrorFile());
+ StreamSP error_sp (GetAsyncErrorStream());
if (error_sp)
{
- HideTopIOHandler();
error_sp->PutCString(data);
error_sp->Flush();
- RefreshTopIOHandler();
}
}
}
@@ -1659,13 +1608,11 @@ Debugger::DefaultEventHandler()
const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get()));
if (data && data[0])
{
- StreamFileSP output_sp (GetOutputFile());
+ StreamSP output_sp (GetAsyncOutputStream());
if (output_sp)
{
- HideTopIOHandler();
output_sp->PutCString(data);
output_sp->Flush();
- RefreshTopIOHandler();
}
}
}
@@ -1729,7 +1676,7 @@ lldb::thread_result_t
Debugger::IOHandlerThread (lldb::thread_arg_t arg)
{
Debugger *debugger = (Debugger *)arg;
- debugger->ExecuteIOHanders();
+ debugger->ExecuteIOHandlers();
debugger->StopEventHandlerThread();
return NULL;
}
diff --git a/source/Core/Disassembler.cpp b/source/Core/Disassembler.cpp
index 14fbee149a52..f96232fcceeb 100644
--- a/source/Core/Disassembler.cpp
+++ b/source/Core/Disassembler.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/Disassembler.h"
// C Includes
@@ -421,6 +419,47 @@ Disassembler::PrintInstructions
}
const uint32_t scope = eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;
const bool use_inline_block_range = false;
+
+ const FormatEntity::Entry *disassembly_format = NULL;
+ FormatEntity::Entry format;
+ if (exe_ctx.HasTargetScope())
+ {
+ disassembly_format = exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat ();
+ }
+ else
+ {
+ FormatEntity::Parse("${addr}: ", format);
+ disassembly_format = &format;
+ }
+
+ // First pass: step through the list of instructions,
+ // find how long the initial addresses strings are, insert padding
+ // in the second pass so the opcodes all line up nicely.
+ size_t address_text_size = 0;
+ for (size_t i = 0; i < num_instructions_found; ++i)
+ {
+ Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get();
+ if (inst)
+ {
+ const Address &addr = inst->GetAddress();
+ ModuleSP module_sp (addr.GetModule());
+ if (module_sp)
+ {
+ const uint32_t resolve_mask = eSymbolContextFunction | eSymbolContextSymbol;
+ uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc);
+ if (resolved_mask)
+ {
+ StreamString strmstr;
+ Debugger::FormatDisassemblerAddress (disassembly_format, &sc, NULL, &exe_ctx, &addr, strmstr);
+ size_t cur_line = strmstr.GetSizeOfLastLine();
+ if (cur_line > address_text_size)
+ address_text_size = cur_line;
+ }
+ sc.Clear(false);
+ }
+ }
+ }
+
for (size_t i = 0; i < num_instructions_found; ++i)
{
Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get();
@@ -448,7 +487,7 @@ Disassembler::PrintInstructions
if (offset != 0)
strm.EOL();
- sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false, false);
+ sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false, false, true);
strm.EOL();
if (sc.comp_unit && sc.line_entry.IsValid())
@@ -471,7 +510,7 @@ Disassembler::PrintInstructions
}
const bool show_bytes = (options & eOptionShowBytes) != 0;
- inst->Dump (&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, NULL);
+ inst->Dump (&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, NULL, address_text_size);
strm.EOL();
}
else
@@ -509,7 +548,7 @@ Disassembler::Disassemble
}
else if (sc.symbol && sc.symbol->ValueIsAddress())
{
- range.GetBaseAddress() = sc.symbol->GetAddress();
+ range.GetBaseAddress() = sc.symbol->GetAddressRef();
range.SetByteSize (sc.symbol->GetByteSize());
}
else
@@ -561,7 +600,8 @@ Instruction::Dump (lldb_private::Stream *s,
const ExecutionContext* exe_ctx,
const SymbolContext *sym_ctx,
const SymbolContext *prev_sym_ctx,
- const FormatEntity::Entry *disassembly_addr_format)
+ const FormatEntity::Entry *disassembly_addr_format,
+ size_t max_address_text_size)
{
size_t opcode_column_width = 7;
const size_t operand_column_width = 25;
@@ -573,6 +613,7 @@ Instruction::Dump (lldb_private::Stream *s,
if (show_address)
{
Debugger::FormatDisassemblerAddress (disassembly_addr_format, sym_ctx, prev_sym_ctx, exe_ctx, &m_address, ss);
+ ss.FillLastLineToColumn (max_address_text_size, ' ');
}
if (show_bytes)
@@ -683,7 +724,7 @@ Instruction::ReadArray (FILE *in_file, Stream *out_stream, OptionValue::Type dat
{
case OptionValue::eTypeUInt64:
data_value_sp.reset (new OptionValueUInt64 (0, 0));
- data_value_sp->SetValueFromCString (value.c_str());
+ data_value_sp->SetValueFromString (value);
break;
// Other types can be added later as needed.
default:
@@ -791,7 +832,7 @@ Instruction::ReadDictionary (FILE *in_file, Stream *out_stream)
else if ((value[0] == '0') && (value[1] == 'x'))
{
value_sp.reset (new OptionValueUInt64 (0, 0));
- value_sp->SetValueFromCString (value.c_str());
+ value_sp->SetValueFromString (value);
}
else
{
@@ -999,7 +1040,7 @@ InstructionList::Dump (Stream *s,
{
if (pos != begin)
s->EOL();
- (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, NULL, NULL, disassembly_format);
+ (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, NULL, NULL, disassembly_format, 0);
}
}
@@ -1018,12 +1059,13 @@ InstructionList::Append (lldb::InstructionSP &inst_sp)
}
uint32_t
-InstructionList::GetIndexOfNextBranchInstruction(uint32_t start) const
+InstructionList::GetIndexOfNextBranchInstruction(uint32_t start, Target &target) const
{
size_t num_instructions = m_instructions.size();
uint32_t next_branch = UINT32_MAX;
- for (size_t i = start; i < num_instructions; i++)
+ size_t i;
+ for (i = start; i < num_instructions; i++)
{
if (m_instructions[i]->DoesBranch())
{
@@ -1031,6 +1073,52 @@ InstructionList::GetIndexOfNextBranchInstruction(uint32_t start) const
break;
}
}
+
+ // Hexagon needs the first instruction of the packet with the branch.
+ // Go backwards until we find an instruction marked end-of-packet, or
+ // until we hit start.
+ if (target.GetArchitecture().GetTriple().getArch() == llvm::Triple::hexagon)
+ {
+ // If we didn't find a branch, find the last packet start.
+ if (next_branch == UINT32_MAX)
+ {
+ i = num_instructions - 1;
+ }
+
+ while (i > start)
+ {
+ --i;
+
+ Error error;
+ uint32_t inst_bytes;
+ bool prefer_file_cache = false; // Read from process if process is running
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ target.ReadMemory(m_instructions[i]->GetAddress(),
+ prefer_file_cache,
+ &inst_bytes,
+ sizeof(inst_bytes),
+ error,
+ &load_addr);
+ // If we have an error reading memory, return start
+ if (!error.Success())
+ return start;
+ // check if this is the last instruction in a packet
+ // bits 15:14 will be 11b or 00b for a duplex
+ if (((inst_bytes & 0xC000) == 0xC000) ||
+ ((inst_bytes & 0xC000) == 0x0000))
+ {
+ // instruction after this should be the start of next packet
+ next_branch = i + 1;
+ break;
+ }
+ }
+
+ if (next_branch == UINT32_MAX)
+ {
+ // We couldn't find the previous packet, so return start
+ next_branch = start;
+ }
+ }
return next_branch;
}
diff --git a/source/Core/DynamicLoader.cpp b/source/Core/DynamicLoader.cpp
index 1f545b727a1e..ffd7425f5231 100644
--- a/source/Core/DynamicLoader.cpp
+++ b/source/Core/DynamicLoader.cpp
@@ -186,6 +186,24 @@ DynamicLoader::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, a
{
UpdateLoadedSections(module_sp, link_map_addr, base_addr);
}
+ else
+ {
+ // Try to fetch the load address of the file from the process. It can be different from the
+ // address reported by the linker in case of a file with fixed load address because the
+ // linker reports the bias between the load address specified in the file and the actual
+ // load address it loaded the file.
+ bool is_loaded;
+ lldb::addr_t load_addr;
+ Error error = m_process->GetFileLoadAddress(file, is_loaded, load_addr);
+ if (error.Fail() || !is_loaded)
+ load_addr = base_addr;
+
+ if ((module_sp = m_process->ReadModuleFromMemory(file, load_addr)))
+ {
+ UpdateLoadedSections(module_sp, link_map_addr, base_addr);
+ target.GetImages().AppendIfNeeded(module_sp);
+ }
+ }
return module_sp;
}
diff --git a/source/Core/Error.cpp b/source/Core/Error.cpp
index 5b0bbe273603..ce055826af2c 100644
--- a/source/Core/Error.cpp
+++ b/source/Core/Error.cpp
@@ -21,10 +21,6 @@
#include <cerrno>
#include <cstdarg>
-#if (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) && defined (__APPLE__)
-#include <SpringBoardServices/SpringBoardServer.h>
-#endif
-
using namespace lldb;
using namespace lldb_private;
diff --git a/source/Core/FastDemangle.cpp b/source/Core/FastDemangle.cpp
index 53e8972e8048..0f12af2783db 100644
--- a/source/Core/FastDemangle.cpp
+++ b/source/Core/FastDemangle.cpp
@@ -383,10 +383,19 @@ private:
char *end_m_write_ptr = m_write_ptr + content_length;
if (end_m_write_ptr > m_buffer_end)
{
- GrowBuffer(end_m_write_ptr - m_buffer_end);
+ if (content >= m_buffer && content < m_buffer_end)
+ {
+ long offset = content - m_buffer;
+ GrowBuffer (end_m_write_ptr - m_buffer_end);
+ content = m_buffer + offset;
+ }
+ else
+ {
+ GrowBuffer (end_m_write_ptr - m_buffer_end);
+ }
end_m_write_ptr = m_write_ptr + content_length;
}
- memcpy(m_write_ptr, content, content_length);
+ memcpy (m_write_ptr, content, content_length);
m_write_ptr = end_m_write_ptr;
}
#define WRITE(x) Write(x, sizeof (x) - 1)
diff --git a/source/Core/FileLineResolver.cpp b/source/Core/FileLineResolver.cpp
index b1346bbdd812..e8ef87f009d9 100644
--- a/source/Core/FileLineResolver.cpp
+++ b/source/Core/FileLineResolver.cpp
@@ -10,7 +10,6 @@
#include "lldb/Core/FileLineResolver.h"
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
diff --git a/source/Core/FormatEntity.cpp b/source/Core/FormatEntity.cpp
index 48b2c2ddbf72..2ebe95747bc0 100644
--- a/source/Core/FormatEntity.cpp
+++ b/source/Core/FormatEntity.cpp
@@ -13,6 +13,7 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Language.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamString.h"
@@ -20,6 +21,7 @@
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/Block.h"
@@ -94,7 +96,9 @@ static FormatEntity::Entry::Definition g_function_child_entries[] =
ENTRY ("addr-offset" , FunctionAddrOffset , UInt64),
ENTRY ("concrete-only-addr-offset-no-padding", FunctionAddrOffsetConcrete, UInt64),
ENTRY ("line-offset" , FunctionLineOffset , UInt64),
- ENTRY ("pc-offset" , FunctionPCOffset , UInt64)
+ ENTRY ("pc-offset" , FunctionPCOffset , UInt64),
+ ENTRY ("initial-function" , FunctionInitial , None),
+ ENTRY ("changed" , FunctionChanged , None)
};
static FormatEntity::Entry::Definition g_line_child_entries[] =
@@ -207,6 +211,7 @@ static FormatEntity::Entry::Definition g_top_level_entries[] =
ENTRY_CHILDREN ("ansi" , Invalid , None , g_ansi_entries),
ENTRY ("current-pc-arrow" , CurrentPCArrow , CString ),
ENTRY_CHILDREN ("file" , File , CString , g_file_child_entries),
+ ENTRY ("language" , Lang , CString),
ENTRY_CHILDREN ("frame" , Invalid , None , g_frame_child_entries),
ENTRY_CHILDREN ("function" , Invalid , None , g_function_child_entries),
ENTRY_CHILDREN ("line" , Invalid , None , g_line_child_entries),
@@ -318,6 +323,7 @@ FormatEntity::Entry::TypeToCString (Type t)
ENUM_TO_CSTR(ScriptTarget);
ENUM_TO_CSTR(ModuleFile);
ENUM_TO_CSTR(File);
+ ENUM_TO_CSTR(Lang);
ENUM_TO_CSTR(FrameIndex);
ENUM_TO_CSTR(FrameRegisterPC);
ENUM_TO_CSTR(FrameRegisterSP);
@@ -335,6 +341,8 @@ FormatEntity::Entry::TypeToCString (Type t)
ENUM_TO_CSTR(FunctionAddrOffsetConcrete);
ENUM_TO_CSTR(FunctionLineOffset);
ENUM_TO_CSTR(FunctionPCOffset);
+ ENUM_TO_CSTR(FunctionInitial);
+ ENUM_TO_CSTR(FunctionChanged);
ENUM_TO_CSTR(LineEntryFile);
ENUM_TO_CSTR(LineEntryLineNumber);
ENUM_TO_CSTR(LineEntryStartAddress);
@@ -444,7 +452,8 @@ DumpAddressOffsetFromFunction (Stream &s,
const ExecutionContext *exe_ctx,
const Address &format_addr,
bool concrete_only,
- bool no_padding)
+ bool no_padding,
+ bool print_zero_offsets)
{
if (format_addr.IsValid())
{
@@ -468,7 +477,7 @@ DumpAddressOffsetFromFunction (Stream &s,
}
}
else if (sc->symbol && sc->symbol->ValueIsAddress())
- func_addr = sc->symbol->GetAddress();
+ func_addr = sc->symbol->GetAddressRef();
}
if (func_addr.IsValid())
@@ -479,10 +488,15 @@ DumpAddressOffsetFromFunction (Stream &s,
{
addr_t func_file_addr = func_addr.GetFileAddress();
addr_t addr_file_addr = format_addr.GetFileAddress();
- if (addr_file_addr > func_file_addr)
+ if (addr_file_addr > func_file_addr
+ || (addr_file_addr == func_file_addr && print_zero_offsets))
+ {
s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_file_addr - func_file_addr);
+ }
else if (addr_file_addr < func_file_addr)
+ {
s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_file_addr - addr_file_addr);
+ }
return true;
}
else
@@ -492,10 +506,15 @@ DumpAddressOffsetFromFunction (Stream &s,
{
addr_t func_load_addr = func_addr.GetLoadAddress (target);
addr_t addr_load_addr = format_addr.GetLoadAddress (target);
- if (addr_load_addr > func_load_addr)
+ if (addr_load_addr > func_load_addr
+ || (addr_load_addr == func_load_addr && print_zero_offsets))
+ {
s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_load_addr - func_load_addr);
+ }
else if (addr_load_addr < func_load_addr)
+ {
s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_load_addr - addr_load_addr);
+ }
return true;
}
}
@@ -750,7 +769,7 @@ DumpValue (Stream &s,
ValueObject::ExpressionPathAftermath what_next = (do_deref_pointer ?
ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing);
ValueObject::GetValueForExpressionPathOptions options;
- options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().DoAllowSyntheticChildren();
+ options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().SetSyntheticChildrenTraversal(ValueObject::GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both);
ValueObject* target = NULL;
const char* var_name_final_if_array_range = NULL;
size_t close_bracket_index = llvm::StringRef::npos;
@@ -935,11 +954,11 @@ DumpValue (Stream &s,
return false;
if (log)
log->Printf("[Debugger::FormatPrompt] handle as array");
+ StreamString special_directions_stream;
llvm::StringRef special_directions;
if (close_bracket_index != llvm::StringRef::npos && subpath.size() > close_bracket_index)
{
ConstString additional_data (subpath.drop_front(close_bracket_index+1));
- StreamString special_directions_stream;
special_directions_stream.Printf("${%svar%s",
do_deref_pointer ? "*" : "",
additional_data.GetCString());
@@ -1283,13 +1302,11 @@ FormatEntity::Format (const Entry &entry,
// Watch for the special "tid" format...
if (entry.printf_format == "tid")
{
- bool handled = false;
Target &target = thread->GetProcess()->GetTarget();
ArchSpec arch (target.GetArchitecture ());
llvm::Triple::OSType ostype = arch.IsValid() ? arch.GetTriple().getOS() : llvm::Triple::UnknownOS;
if ((ostype == llvm::Triple::FreeBSD) || (ostype == llvm::Triple::Linux))
{
- handled = true;
format = "%" PRIu64;
}
}
@@ -1501,6 +1518,23 @@ FormatEntity::Format (const Entry &entry,
}
return false;
+ case Entry::Type::Lang:
+ if (sc)
+ {
+ CompileUnit *cu = sc->comp_unit;
+ if (cu)
+ {
+ Language lang(cu->GetLanguage());
+ const char *lang_name = lang.AsCString();
+ if (lang_name)
+ {
+ s.PutCString(lang_name);
+ return true;
+ }
+ }
+ }
+ return false;
+
case Entry::Type::FrameIndex:
if (exe_ctx)
{
@@ -1803,7 +1837,7 @@ FormatEntity::Format (const Entry &entry,
case Entry::Type::FunctionAddrOffset:
if (addr)
{
- if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, false, false))
+ if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, false, false, false))
return true;
}
return false;
@@ -1811,13 +1845,13 @@ FormatEntity::Format (const Entry &entry,
case Entry::Type::FunctionAddrOffsetConcrete:
if (addr)
{
- if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, true, true))
+ if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, true, true, true))
return true;
}
return false;
case Entry::Type::FunctionLineOffset:
- if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, sc->line_entry.range.GetBaseAddress(), false, false))
+ if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, sc->line_entry.range.GetBaseAddress(), false, false, false))
return true;
return false;
@@ -1827,12 +1861,18 @@ FormatEntity::Format (const Entry &entry,
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame)
{
- if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, frame->GetFrameCodeAddress(), false, false))
+ if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, frame->GetFrameCodeAddress(), false, false, false))
return true;
}
}
return false;
+ case Entry::Type::FunctionChanged:
+ return function_changed == true;
+
+ case Entry::Type::FunctionInitial:
+ return initial_function == true;
+
case Entry::Type::LineEntryFile:
if (sc && sc->line_entry.IsValid())
{
diff --git a/source/Core/IOHandler.cpp b/source/Core/IOHandler.cpp
index 747fd4411d4d..0246778b0654 100644
--- a/source/Core/IOHandler.cpp
+++ b/source/Core/IOHandler.cpp
@@ -8,8 +8,6 @@
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include <string>
#include "lldb/Breakpoint/BreakpointLocation.h"
@@ -169,6 +167,17 @@ IOHandler::WaitForPop ()
m_popped.WaitForValueEqualTo(true);
}
+void
+IOHandlerStack::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+ if (stream)
+ {
+ Mutex::Locker locker (m_mutex);
+ if (m_top)
+ m_top->PrintAsync (stream, s, len);
+ }
+}
+
IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger,
const char *prompt,
bool default_response) :
@@ -380,7 +389,8 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
m_curr_line_idx (UINT32_MAX),
m_multi_line (multi_line),
m_color_prompts (color_prompts),
- m_interrupt_exits (true)
+ m_interrupt_exits (true),
+ m_editing (false)
{
SetPrompt(prompt);
@@ -474,6 +484,7 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
char buffer[256];
bool done = false;
bool got_line = false;
+ m_editing = true;
while (!done)
{
if (fgets(buffer, sizeof(buffer), in) == NULL)
@@ -508,6 +519,7 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
line.append(buffer, buffer_len);
}
}
+ m_editing = false;
// We might have gotten a newline on a line by itself
// make sure to return true in this case.
return got_line;
@@ -737,47 +749,11 @@ IOHandlerEditline::Run ()
}
void
-IOHandlerEditline::Hide ()
-{
-#ifndef LLDB_DISABLE_LIBEDIT
- if (m_editline_ap)
- m_editline_ap->Hide();
-#endif
-}
-
-
-void
-IOHandlerEditline::Refresh ()
-{
-#ifndef LLDB_DISABLE_LIBEDIT
- if (m_editline_ap)
- {
- m_editline_ap->Refresh();
- }
- else
- {
-#endif
- const char *prompt = GetPrompt();
- if (prompt && prompt[0])
- {
- FILE *out = GetOutputFILE();
- if (out)
- {
- ::fprintf(out, "%s", prompt);
- ::fflush(out);
- }
- }
-#ifndef LLDB_DISABLE_LIBEDIT
- }
-#endif
-}
-
-void
IOHandlerEditline::Cancel ()
{
#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
- m_editline_ap->Interrupt ();
+ m_editline_ap->Cancel ();
#endif
}
@@ -804,6 +780,17 @@ IOHandlerEditline::GotEOF()
#endif
}
+void
+IOHandlerEditline::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+#ifndef LLDB_DISABLE_LIBEDIT
+ if (m_editline_ap)
+ m_editline_ap->PrintAsync(stream, s, len);
+ else
+#endif
+ IOHandler::PrintAsync(stream, s, len);
+}
+
// we may want curses to be disabled for some builds
// for instance, windows
#ifndef LLDB_DISABLE_CURSES
@@ -1080,7 +1067,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
~WindowDelegate()
{
}
-
+
virtual bool
WindowDelegateDraw (Window &window, bool force)
{
@@ -1112,14 +1099,13 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
public:
HelpDialogDelegate (const char *text, KeyHelp *key_help_array);
- virtual
- ~HelpDialogDelegate();
+ ~HelpDialogDelegate() override;
- virtual bool
- WindowDelegateDraw (Window &window, bool force);
+ bool
+ WindowDelegateDraw (Window &window, bool force) override;
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int key);
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int key) override;
size_t
GetNumLines() const
@@ -1787,8 +1773,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
int key_value,
uint64_t identifier);
- virtual ~
- Menu ()
+ ~Menu () override
{
}
@@ -1816,11 +1801,11 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
void
DrawMenuTitle (Window &window, bool highlight);
- virtual bool
- WindowDelegateDraw (Window &window, bool force);
+ bool
+ WindowDelegateDraw (Window &window, bool force) override;
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int key);
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int key) override;
MenuActionResult
ActionPrivate (Menu &menu)
@@ -2924,8 +2909,6 @@ public:
return this;
if (m_children.empty())
return NULL;
- if (static_cast<uint32_t>(m_children.back().m_row_idx) < row_idx)
- return NULL;
if (IsExpanded())
{
for (auto &item : m_children)
@@ -3005,8 +2988,8 @@ public:
return m_max_y - m_min_y;
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
Process *process = exe_ctx.GetProcessPtr();
@@ -3071,14 +3054,14 @@ public:
}
- virtual const char *
- WindowDelegateGetHelpText ()
+ const char *
+ WindowDelegateGetHelpText () override
{
return "Thread window keyboard shortcuts:";
}
- virtual KeyHelp *
- WindowDelegateGetKeyHelp ()
+ KeyHelp *
+ WindowDelegateGetKeyHelp () override
{
static curses::KeyHelp g_source_view_key_help[] = {
{ KEY_UP, "Select previous item" },
@@ -3096,8 +3079,8 @@ public:
return g_source_view_key_help;
}
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int c)
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int c) override
{
switch(c)
{
@@ -3221,12 +3204,12 @@ public:
m_format);
}
- virtual ~FrameTreeDelegate()
+ ~FrameTreeDelegate() override
{
}
- virtual void
- TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
+ void
+ TreeDelegateDrawTreeItem (TreeItem &item, Window &window) override
{
Thread* thread = (Thread*)item.GetUserData();
if (thread)
@@ -3246,14 +3229,14 @@ public:
}
}
}
- virtual void
- TreeDelegateGenerateChildren (TreeItem &item)
+ void
+ TreeDelegateGenerateChildren (TreeItem &item) override
{
// No children for frames yet...
}
- virtual bool
- TreeDelegateItemSelected (TreeItem &item)
+ bool
+ TreeDelegateItemSelected (TreeItem &item) override
{
Thread* thread = (Thread*)item.GetUserData();
if (thread)
@@ -3282,8 +3265,7 @@ public:
m_format);
}
- virtual
- ~ThreadTreeDelegate()
+ ~ThreadTreeDelegate() override
{
}
@@ -3302,8 +3284,8 @@ public:
return ThreadSP();
}
- virtual void
- TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
+ void
+ TreeDelegateDrawTreeItem (TreeItem &item, Window &window) override
{
ThreadSP thread_sp = GetThread (item);
if (thread_sp)
@@ -3317,8 +3299,8 @@ public:
}
}
}
- virtual void
- TreeDelegateGenerateChildren (TreeItem &item)
+ void
+ TreeDelegateGenerateChildren (TreeItem &item) override
{
ProcessSP process_sp = GetProcess ();
if (process_sp && process_sp->IsAlive())
@@ -3355,8 +3337,8 @@ public:
item.ClearChildren();
}
- virtual bool
- TreeDelegateItemSelected (TreeItem &item)
+ bool
+ TreeDelegateItemSelected (TreeItem &item) override
{
ProcessSP process_sp = GetProcess ();
if (process_sp && process_sp->IsAlive())
@@ -3403,8 +3385,7 @@ public:
m_format);
}
- virtual
- ~ThreadsTreeDelegate()
+ ~ThreadsTreeDelegate() override
{
}
@@ -3414,8 +3395,8 @@ public:
return m_debugger.GetCommandInterpreter().GetExecutionContext().GetProcessSP();
}
- virtual void
- TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
+ void
+ TreeDelegateDrawTreeItem (TreeItem &item, Window &window) override
{
ProcessSP process_sp = GetProcess ();
if (process_sp && process_sp->IsAlive())
@@ -3430,8 +3411,8 @@ public:
}
}
- virtual void
- TreeDelegateGenerateChildren (TreeItem &item)
+ void
+ TreeDelegateGenerateChildren (TreeItem &item) override
{
ProcessSP process_sp = GetProcess ();
if (process_sp && process_sp->IsAlive())
@@ -3468,8 +3449,8 @@ public:
item.ClearChildren();
}
- virtual bool
- TreeDelegateItemSelected (TreeItem &item)
+ bool
+ TreeDelegateItemSelected (TreeItem &item) override
{
return false;
}
@@ -3510,8 +3491,7 @@ public:
SetValues (valobj_list);
}
- virtual
- ~ValueObjectListDelegate()
+ ~ValueObjectListDelegate() override
{
}
@@ -3529,8 +3509,8 @@ public:
m_rows.push_back(Row(m_valobj_list.GetValueObjectAtIndex(i), NULL));
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
m_num_rows = 0;
m_min_x = 2;
@@ -3572,8 +3552,8 @@ public:
return true; // Drawing handled
}
- virtual KeyHelp *
- WindowDelegateGetKeyHelp ()
+ KeyHelp *
+ WindowDelegateGetKeyHelp () override
{
static curses::KeyHelp g_source_view_key_help[] = {
{ KEY_UP, "Select previous item" },
@@ -3607,8 +3587,8 @@ public:
}
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int c)
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int c) override
{
switch(c)
{
@@ -3911,19 +3891,18 @@ public:
{
}
- virtual
- ~FrameVariablesWindowDelegate()
+ ~FrameVariablesWindowDelegate() override
{
}
- virtual const char *
- WindowDelegateGetHelpText ()
+ const char *
+ WindowDelegateGetHelpText () override
{
return "Frame variable window keyboard shortcuts:";
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
Process *process = exe_ctx.GetProcessPtr();
@@ -3944,6 +3923,7 @@ public:
return true; // Don't do any updating when we are running
}
}
+
ValueObjectList local_values;
if (frame_block)
@@ -3959,7 +3939,18 @@ public:
const DynamicValueType use_dynamic = eDynamicDontRunTarget;
const size_t num_locals = locals->GetSize();
for (size_t i=0; i<num_locals; ++i)
- local_values.Append(frame->GetValueObjectForFrameVariable (locals->GetVariableAtIndex(i), use_dynamic));
+ {
+ ValueObjectSP value_sp = frame->GetValueObjectForFrameVariable (locals->GetVariableAtIndex(i), use_dynamic);
+ if (value_sp)
+ {
+ ValueObjectSP synthetic_value_sp = value_sp->GetSyntheticValue();
+ if (synthetic_value_sp)
+ local_values.Append(synthetic_value_sp);
+ else
+ local_values.Append(value_sp);
+
+ }
+ }
// Update the values
SetValues(local_values);
}
@@ -3990,20 +3981,19 @@ public:
m_debugger (debugger)
{
}
-
- virtual
+
~RegistersWindowDelegate()
{
}
- virtual const char *
- WindowDelegateGetHelpText ()
+ const char *
+ WindowDelegateGetHelpText () override
{
return "Register window keyboard shortcuts:";
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
StackFrame *frame = exe_ctx.GetFramePtr();
@@ -4309,18 +4299,18 @@ public:
{
}
- virtual
~ApplicationDelegate ()
{
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
return false; // Drawing not handled, let standard window drawing happen
}
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int key)
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int key) override
{
switch (key)
{
@@ -4342,8 +4332,8 @@ public:
}
- virtual const char *
- WindowDelegateGetHelpText ()
+ const char *
+ WindowDelegateGetHelpText () override
{
return "Welcome to the LLDB curses GUI.\n\n"
"Press the TAB key to change the selected view.\n"
@@ -4351,8 +4341,8 @@ public:
"Common key bindings for all views:";
}
- virtual KeyHelp *
- WindowDelegateGetKeyHelp ()
+ KeyHelp *
+ WindowDelegateGetKeyHelp () override
{
static curses::KeyHelp g_source_view_key_help[] = {
{ '\t', "Select next view" },
@@ -4370,8 +4360,8 @@ public:
return g_source_view_key_help;
}
- virtual MenuActionResult
- MenuDelegateAction (Menu &menu)
+ MenuActionResult
+ MenuDelegateAction (Menu &menu) override
{
switch (menu.GetIdentifier())
{
@@ -4430,7 +4420,7 @@ public:
{
Process *process = exe_ctx.GetProcessPtr();
if (process && process->IsAlive())
- process->Destroy();
+ process->Destroy(false);
}
}
return MenuActionResult::Handled;
@@ -4647,12 +4637,12 @@ public:
m_format);
}
- virtual
~StatusBarWindowDelegate ()
{
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
Process *process = exe_ctx.GetProcessPtr();
@@ -4723,8 +4713,7 @@ public:
{
}
- virtual
- ~SourceFileWindowDelegate()
+ ~SourceFileWindowDelegate() override
{
}
@@ -4740,14 +4729,14 @@ public:
return m_max_y - m_min_y;
}
- virtual const char *
- WindowDelegateGetHelpText ()
+ const char *
+ WindowDelegateGetHelpText () override
{
return "Source/Disassembly window keyboard shortcuts:";
}
- virtual KeyHelp *
- WindowDelegateGetKeyHelp ()
+ KeyHelp *
+ WindowDelegateGetKeyHelp () override
{
static curses::KeyHelp g_source_view_key_help[] = {
{ KEY_RETURN, "Run to selected line with one shot breakpoint" },
@@ -4773,8 +4762,8 @@ public:
return g_source_view_key_help;
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
Process *process = exe_ctx.GetProcessPtr();
@@ -5259,8 +5248,8 @@ public:
return 0;
}
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int c)
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int c) override
{
const uint32_t num_visible_lines = NumVisibleLines();
const size_t num_lines = GetNumLines ();
@@ -5324,7 +5313,8 @@ public:
eLazyBoolCalculate, // Check inlines using global setting
eLazyBoolCalculate, // Skip prologue using global setting,
false, // internal
- false); // request_hardware
+ false, // request_hardware
+ eLazyBoolCalculate); // move_to_nearest_code
// Make breakpoint one shot
bp_sp->GetOptions()->SetOneShot(true);
exe_ctx.GetProcessRef().Resume();
@@ -5359,7 +5349,8 @@ public:
eLazyBoolCalculate, // Check inlines using global setting
eLazyBoolCalculate, // Skip prologue using global setting,
false, // internal
- false); // request_hardware
+ false, // request_hardware
+ eLazyBoolCalculate); // move_to_nearest_code
}
}
else if (m_selected_line < GetNumDisassemblyLines())
@@ -5390,7 +5381,7 @@ public:
{
ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
if (exe_ctx.HasProcessScope())
- exe_ctx.GetProcessRef().Destroy();
+ exe_ctx.GetProcessRef().Destroy(false);
}
return eKeyHandled;
@@ -5611,17 +5602,6 @@ IOHandlerCursesGUI::~IOHandlerCursesGUI ()
}
void
-IOHandlerCursesGUI::Hide ()
-{
-}
-
-
-void
-IOHandlerCursesGUI::Refresh ()
-{
-}
-
-void
IOHandlerCursesGUI::Cancel ()
{
}
diff --git a/source/Core/Language.cpp b/source/Core/Language.cpp
index 1ffd5aadc526..1cc4b8a0dc9c 100644
--- a/source/Core/Language.cpp
+++ b/source/Core/Language.cpp
@@ -46,7 +46,25 @@ g_languages[] =
{ { "objc++" , NULL , "Objective-C++" } },
{ { "upc" , NULL , "Unified Parallel C" } },
{ { "d" , NULL , "D" } },
- { { "python" , NULL , "Python" } }
+ { { "python" , NULL , "Python" } },
+ { { "opencl" , "OpenCL" , "OpenCL" } },
+ { { "go" , "Go" , "Go" } },
+ { { "modula3" , "Modula3" , "Modula 3" } },
+ { { "haskell" , "Haskell" , "Haskell" } },
+ { { "c++03" , "C_plus_plus_03" , "ISO C++:2003" } },
+ { { "c++11" , "C_plus_plus_11" , "ISO C++:2011" } },
+ { { "ocaml" , "OCaml" , "OCaml" } },
+ { { "rust" , "Rust" , "Rust" } },
+ { { "c11" , "C11" , "ISO C:2011" } },
+ { { "swift" , "Swift" , "Swift" } },
+ { { "julia" , "Julia" , "Julia" } },
+ { { "dylan" , "Dylan" , "Dylan" } },
+ { { "c++14" , "C_plus_plus_14" , "ISO C++:2014" } },
+ { { "f03" , "Fortran03" , "ISO Fortran 2003" } },
+ { { "f08" , "Fortran08" , "ISO Fortran 2008" } },
+ // Vendor Extensions
+ { { "mipsassem" , "Mips_Assembler" , "Mips Assembler" } },
+ { { "renderscript" , "RenderScript" , "RenderScript" } }
};
static const size_t g_num_languages = llvm::array_lengthof(g_languages);
diff --git a/source/Core/Listener.cpp b/source/Core/Listener.cpp
index f71d766e0a1c..34475498d48e 100644
--- a/source/Core/Listener.cpp
+++ b/source/Core/Listener.cpp
@@ -18,7 +18,6 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Event.h"
#include "lldb/Host/TimeValue.h"
-#include "lldb/lldb-private-log.h"
#include <algorithm>
using namespace lldb;
diff --git a/source/Core/Log.cpp b/source/Core/Log.cpp
index fe4cfb366c88..6acd50eec76a 100644
--- a/source/Core/Log.cpp
+++ b/source/Core/Log.cpp
@@ -27,8 +27,11 @@
#include "lldb/Host/ThisThread.h"
#include "lldb/Host/TimeValue.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/NameMatches.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
using namespace lldb;
using namespace lldb_private;
@@ -74,6 +77,23 @@ Log::GetMask() const
return m_mask_bits;
}
+void
+Log::PutCString(const char *cstr)
+{
+ Printf("%s", cstr);
+}
+
+//----------------------------------------------------------------------
+// Simple variable argument logging with flags.
+//----------------------------------------------------------------------
+void
+Log::Printf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
+}
//----------------------------------------------------------------------
// All logging eventually boils down to this function call. If we have
@@ -81,7 +101,7 @@ Log::GetMask() const
// a valid file handle, we also log to the file.
//----------------------------------------------------------------------
void
-Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
+Log::VAPrintf(const char *format, va_list args)
{
// Make a copy of our stream shared pointer in case someone disables our
// log while we are logging and releases the stream
@@ -90,10 +110,6 @@ Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
{
static uint32_t g_sequence_id = 0;
StreamString header;
- // Enabling the thread safe logging actually deadlocks right now.
- // Need to fix this at some point.
-// static Mutex g_LogThreadedMutex(Mutex::eMutexTypeRecursive);
-// Mutex::Locker locker (g_LogThreadedMutex);
// Add a sequence ID if requested
if (m_options.Test (LLDB_LOG_OPTION_PREPEND_SEQUENCE))
@@ -103,7 +119,7 @@ Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
if (m_options.Test (LLDB_LOG_OPTION_PREPEND_TIMESTAMP))
{
TimeValue now = TimeValue::Now();
- header.Printf ("%9d.%6.6d ", now.seconds(), now.nanoseconds());
+ header.Printf ("%9d.%09.9d ", now.seconds(), now.nanoseconds());
}
// Add the process and thread if requested
@@ -120,51 +136,29 @@ Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
}
header.PrintfVarArg (format, args);
- stream_sp->Printf("%s\n", header.GetData());
-
- if (m_options.Test (LLDB_LOG_OPTION_BACKTRACE))
- Host::Backtrace (*stream_sp, 1024);
- stream_sp->Flush();
- }
-}
-
-
-void
-Log::PutCString (const char *cstr)
-{
- Printf ("%s", cstr);
-}
-
-
-//----------------------------------------------------------------------
-// Simple variable argument logging with flags.
-//----------------------------------------------------------------------
-void
-Log::Printf(const char *format, ...)
-{
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (0, format, args);
- va_end (args);
-}
-
-void
-Log::VAPrintf (const char *format, va_list args)
-{
- PrintfWithFlagsVarArg (0, format, args);
-}
+ header.PutCString("\n");
+ if (m_options.Test(LLDB_LOG_OPTION_BACKTRACE))
+ {
+ std::string back_trace;
+ llvm::raw_string_ostream stream(back_trace);
+ llvm::sys::PrintStackTrace(stream);
+ header.PutCString(back_trace.c_str());
+ }
-//----------------------------------------------------------------------
-// Simple variable argument logging with flags.
-//----------------------------------------------------------------------
-void
-Log::PrintfWithFlags (uint32_t flags, const char *format, ...)
-{
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (flags, format, args);
- va_end (args);
+ if (m_options.Test(LLDB_LOG_OPTION_THREADSAFE))
+ {
+ static Mutex g_LogThreadedMutex(Mutex::eMutexTypeRecursive);
+ Mutex::Locker locker(g_LogThreadedMutex);
+ stream_sp->PutCString(header.GetString().c_str());
+ stream_sp->Flush();
+ }
+ else
+ {
+ stream_sp->PutCString(header.GetString().c_str());
+ stream_sp->Flush();
+ }
+ }
}
//----------------------------------------------------------------------
@@ -172,15 +166,15 @@ Log::PrintfWithFlags (uint32_t flags, const char *format, ...)
// a non-zero value.
//----------------------------------------------------------------------
void
-Log::Debug (const char *format, ...)
+Log::Debug(const char *format, ...)
{
- if (GetOptions().Test(LLDB_LOG_OPTION_DEBUG))
- {
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (LLDB_LOG_FLAG_DEBUG, format, args);
- va_end (args);
- }
+ if (!GetOptions().Test(LLDB_LOG_OPTION_DEBUG))
+ return;
+
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
}
@@ -189,15 +183,15 @@ Log::Debug (const char *format, ...)
// a non-zero value.
//----------------------------------------------------------------------
void
-Log::DebugVerbose (const char *format, ...)
+Log::DebugVerbose(const char *format, ...)
{
- if (GetOptions().AllSet (LLDB_LOG_OPTION_DEBUG | LLDB_LOG_OPTION_VERBOSE))
- {
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (LLDB_LOG_FLAG_DEBUG | LLDB_LOG_FLAG_VERBOSE, format, args);
- va_end (args);
- }
+ if (!GetOptions().AllSet(LLDB_LOG_OPTION_DEBUG | LLDB_LOG_OPTION_VERBOSE))
+ return;
+
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
}
@@ -205,55 +199,63 @@ Log::DebugVerbose (const char *format, ...)
// Log only if all of the bits are set
//----------------------------------------------------------------------
void
-Log::LogIf (uint32_t bits, const char *format, ...)
+Log::LogIf(uint32_t bits, const char *format, ...)
{
- if (m_options.AllSet (bits))
- {
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (0, format, args);
- va_end (args);
- }
+ if (!m_options.AllSet(bits))
+ return;
+
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
}
//----------------------------------------------------------------------
// Printing of errors that are not fatal.
//----------------------------------------------------------------------
void
-Log::Error (const char *format, ...)
+Log::Error(const char *format, ...)
{
- char *arg_msg = NULL;
va_list args;
- va_start (args, format);
- ::vasprintf (&arg_msg, format, args);
- va_end (args);
+ va_start(args, format);
+ VAError(format, args);
+ va_end(args);
+}
- if (arg_msg != NULL)
- {
- PrintfWithFlags (LLDB_LOG_FLAG_ERROR, "error: %s", arg_msg);
- free (arg_msg);
- }
+
+void
+Log::VAError(const char *format, va_list args)
+{
+ char *arg_msg = nullptr;
+ ::vasprintf(&arg_msg, format, args);
+
+ if (arg_msg == nullptr)
+ return;
+
+ Printf("error: %s", arg_msg);
+ free(arg_msg);
}
+
//----------------------------------------------------------------------
// Printing of errors that ARE fatal. Exit with ERR exit code
// immediately.
//----------------------------------------------------------------------
void
-Log::FatalError (int err, const char *format, ...)
+Log::FatalError(int err, const char *format, ...)
{
- char *arg_msg = NULL;
+ char *arg_msg = nullptr;
va_list args;
- va_start (args, format);
- ::vasprintf (&arg_msg, format, args);
- va_end (args);
+ va_start(args, format);
+ ::vasprintf(&arg_msg, format, args);
+ va_end(args);
- if (arg_msg != NULL)
+ if (arg_msg != nullptr)
{
- PrintfWithFlags (LLDB_LOG_FLAG_ERROR | LLDB_LOG_FLAG_FATAL, "error: %s", arg_msg);
- ::free (arg_msg);
+ Printf("error: %s", arg_msg);
+ ::free(arg_msg);
}
- ::exit (err);
+ ::exit(err);
}
@@ -262,15 +264,15 @@ Log::FatalError (int err, const char *format, ...)
// enabled.
//----------------------------------------------------------------------
void
-Log::Verbose (const char *format, ...)
+Log::Verbose(const char *format, ...)
{
- if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
- {
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (LLDB_LOG_FLAG_VERBOSE, format, args);
- va_end (args);
- }
+ if (!m_options.Test(LLDB_LOG_OPTION_VERBOSE))
+ return;
+
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
}
//----------------------------------------------------------------------
@@ -278,40 +280,40 @@ Log::Verbose (const char *format, ...)
// enabled.
//----------------------------------------------------------------------
void
-Log::WarningVerbose (const char *format, ...)
+Log::WarningVerbose(const char *format, ...)
{
- if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
- {
- char *arg_msg = NULL;
- va_list args;
- va_start (args, format);
- ::vasprintf (&arg_msg, format, args);
- va_end (args);
+ if (!m_options.Test(LLDB_LOG_OPTION_VERBOSE))
+ return;
- if (arg_msg != NULL)
- {
- PrintfWithFlags (LLDB_LOG_FLAG_WARNING | LLDB_LOG_FLAG_VERBOSE, "warning: %s", arg_msg);
- free (arg_msg);
- }
- }
+ char *arg_msg = nullptr;
+ va_list args;
+ va_start(args, format);
+ ::vasprintf(&arg_msg, format, args);
+ va_end(args);
+
+ if (arg_msg == nullptr)
+ return;
+
+ Printf("warning: %s", arg_msg);
+ free(arg_msg);
}
//----------------------------------------------------------------------
// Printing of warnings that are not fatal.
//----------------------------------------------------------------------
void
-Log::Warning (const char *format, ...)
+Log::Warning(const char *format, ...)
{
- char *arg_msg = NULL;
+ char *arg_msg = nullptr;
va_list args;
- va_start (args, format);
- ::vasprintf (&arg_msg, format, args);
- va_end (args);
+ va_start(args, format);
+ ::vasprintf(&arg_msg, format, args);
+ va_end(args);
- if (arg_msg != NULL)
- {
- PrintfWithFlags (LLDB_LOG_FLAG_WARNING, "warning: %s", arg_msg);
- free (arg_msg);
- }
+ if (arg_msg == nullptr)
+ return;
+
+ Printf("warning: %s", arg_msg);
+ free(arg_msg);
}
typedef std::map <ConstString, Log::Callbacks> CallbackMap;
@@ -363,6 +365,40 @@ Log::GetLogChannelCallbacks (const ConstString &channel, Log::Callbacks &log_cal
return false;
}
+bool
+Log::EnableLogChannel(lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ const char *channel,
+ const char **categories,
+ Stream &error_stream)
+{
+ Log::Callbacks log_callbacks;
+ if (Log::GetLogChannelCallbacks (ConstString(channel), log_callbacks))
+ {
+ log_callbacks.enable (log_stream_sp, log_options, categories, &error_stream);
+ return true;
+ }
+
+ LogChannelSP log_channel_sp (LogChannel::FindPlugin (channel));
+ if (log_channel_sp)
+ {
+ if (log_channel_sp->Enable (log_stream_sp, log_options, &error_stream, categories))
+ {
+ return true;
+ }
+ else
+ {
+ error_stream.Printf ("Invalid log channel '%s'.\n", channel);
+ return false;
+ }
+ }
+ else
+ {
+ error_stream.Printf ("Invalid log channel '%s'.\n", channel);
+ return false;
+ }
+}
+
void
Log::EnableAllLogChannels
(
diff --git a/source/lldb-log.cpp b/source/Core/Logging.cpp
index 463de137f623..412536adbb34 100644
--- a/source/lldb-log.cpp
+++ b/source/Core/Logging.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Logging.h"
// C Includes
// C++ Includes
@@ -25,7 +25,7 @@ using namespace lldb_private;
// We want to avoid global constructors where code needs to be run so here we
// control access to our static g_log_sp by hiding it in a singleton function
-// that will construct the static g_lob_sp the first time this function is
+// that will construct the static g_lob_sp the first time this function is
// called.
static std::atomic<bool> g_log_enabled {false};
@@ -147,13 +147,13 @@ lldb_private::DisableLog (const char **categories, Stream *feedback_strm)
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 if (0 == ::strcasecmp(arg, "language")) flag_bits &= ~LIBLLDB_LOG_LANGUAGE;
else
{
feedback_strm->Printf ("error: unrecognized log category '%s'\n", arg);
ListLogCategories (feedback_strm);
return;
}
-
}
}
log->GetMask().Reset (flag_bits);
@@ -223,6 +223,7 @@ lldb_private::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const ch
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 if (0 == ::strcasecmp(arg, "language")) flag_bits |= LIBLLDB_LOG_LANGUAGE;
else
{
feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
@@ -255,6 +256,7 @@ lldb_private::ListLogCategories (Stream *strm)
" expr - log expressions\n"
" host - log host activities\n"
" jit - log JIT events in the target\n"
+ " language - log language runtime events\n"
" mmap - log mmap related activities\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"
diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp
index e1598d30e4e5..3e1a8bb89139 100644
--- a/source/Core/Mangled.cpp
+++ b/source/Core/Mangled.cpp
@@ -13,6 +13,8 @@
#if defined(_MSC_VER)
#include "lldb/Host/windows/windows.h"
#include <Dbghelp.h>
+#pragma comment(lib, "dbghelp.lib")
+#define LLDB_USE_BUILTIN_DEMANGLER
#elif defined (__FreeBSD__)
#define LLDB_USE_BUILTIN_DEMANGLER
#else
@@ -23,4960 +25,9 @@
// 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
-// revision 199944.
-//
-// Changes include:
-// - remove the "__cxxabiv1" namespace
-// - stripped GCC attributes()
-// - removed extern "C" from the cxa_demangle function
-// - Changed the scope of the unnamed namespace to include cxa_demangle
-// function.
-// - Added "#undef _LIBCPP_EXTERN_TEMPLATE" to avoid warning
-//----------------------------------------------------------------------
-
-#undef _LIBCPP_EXTERN_TEMPLATE // Avoid warning below
-
-//===-------------------------- cxa_demangle.cpp --------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#define _LIBCPP_EXTERN_TEMPLATE(...)
-#define _LIBCPP_NO_EXCEPTIONS
+#include "lldb/Core/FastDemangle.h"
+#include "lldb/Core/CxaDemangle.h"
-#include <vector>
-#include <algorithm>
-#include <string>
-#include <numeric>
-#include <cstdlib>
-#include <cstring>
-#include <cctype>
-
-
-namespace
-{
-
-enum
-{
- unknown_error = -4,
- invalid_args = -3,
- invalid_mangled_name,
- memory_alloc_failure,
- success
-};
-
-template <class C>
- const char* parse_type(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_encoding(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_name(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_expression(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_template_args(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_operator_name(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_unqualified_name(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_decltype(const char* first, const char* last, C& db);
-
-template <class C>
-void
-print_stack(const C& db)
-{
- printf("---------\n");
- printf("names:\n");
- for (auto& s : db.names)
- printf("{%s#%s}\n", s.first.c_str(), s.second.c_str());
- int i = -1;
- printf("subs:\n");
- for (auto& v : db.subs)
- {
- if (i >= 0)
- printf("S%i_ = {", i);
- else
- printf("S_ = {");
- for (auto& s : v)
- printf("{%s#%s}", s.first.c_str(), s.second.c_str());
- printf("}\n");
- ++i;
- }
- printf("template_param:\n");
- for (auto& t : db.template_param)
- {
- printf("--\n");
- i = -1;
- for (auto& v : t)
- {
- if (i >= 0)
- printf("T%i_ = {", i);
- else
- printf("T_ = {");
- for (auto& s : v)
- printf("{%s#%s}", s.first.c_str(), s.second.c_str());
- printf("}\n");
- ++i;
- }
- }
- printf("---------\n\n");
-}
-
-template <class C>
-void
-print_state(const char* msg, const char* first, const char* last, const C& db)
-{
- printf("%s: ", msg);
- for (; first != last; ++first)
- printf("%c", *first);
- printf("\n");
- print_stack(db);
-}
-
-// <number> ::= [n] <non-negative decimal integer>
-
-const char*
-parse_number(const char* first, const char* last)
-{
- if (first != last)
- {
- const char* t = first;
- if (*t == 'n')
- ++t;
- if (t != last)
- {
- if (*t == '0')
- {
- first = t+1;
- }
- else if ('1' <= *t && *t <= '9')
- {
- first = t+1;
- while (first != last && std::isdigit(*first))
- ++first;
- }
- }
- }
- return first;
-}
-
-template <class Float>
-struct float_data;
-
-template <>
-struct float_data<float>
-{
- static const size_t mangled_size = 8;
- static const size_t max_demangled_size = 24;
- static constexpr const char* spec = "%af";
-};
-
-constexpr const char* float_data<float>::spec;
-
-template <>
-struct float_data<double>
-{
- static const size_t mangled_size = 16;
- static const size_t max_demangled_size = 32;
- static constexpr const char* spec = "%a";
-};
-
-constexpr const char* float_data<double>::spec;
-
-template <>
-struct float_data<long double>
-{
- static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
- static const size_t max_demangled_size = 40;
- static constexpr const char* spec = "%LaL";
-};
-
-constexpr const char* float_data<long double>::spec;
-
-template <class Float, class C>
-const char*
-parse_floating_number(const char* first, const char* last, C& db)
-{
- const size_t N = float_data<Float>::mangled_size;
- if (static_cast<std::size_t>(last - first) > N)
- {
- last = first + N;
- union
- {
- Float value;
- char buf[sizeof(Float)];
- };
- const char* t = first;
- char* e = buf;
- for (; t != last; ++t, ++e)
- {
- if (!isxdigit(*t))
- return first;
- unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
- static_cast<unsigned>(*t - 'a' + 10);
- ++t;
- unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
- static_cast<unsigned>(*t - 'a' + 10);
- *e = static_cast<char>((d1 << 4) + d0);
- }
- if (*t == 'E')
- {
-#if __LITTLE_ENDIAN__
- std::reverse(buf, e);
-#endif
- char num[float_data<Float>::max_demangled_size] = {0};
- int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);
- if (static_cast<std::size_t>(n) >= sizeof(num))
- return first;
- db.names.push_back(typename C::String(num, static_cast<std::size_t>(n)));
- first = t+1;
- }
- }
- return first;
-}
-
-// <source-name> ::= <positive length number> <identifier>
-
-template <class C>
-const char*
-parse_source_name(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- char c = *first;
- if (isdigit(c) && first+1 != last)
- {
- const char* t = first+1;
- size_t n = static_cast<size_t>(c - '0');
- for (c = *t; isdigit(c); c = *t)
- {
- n = n * 10 + static_cast<size_t>(c - '0');
- if (++t == last)
- return first;
- }
- if (static_cast<size_t>(last - t) >= n)
- {
- typename C::String r(t, n);
- if (r.substr(0, 10) == "_GLOBAL__N")
- db.names.push_back("(anonymous namespace)");
- else
- db.names.push_back(std::move(r));
- first = t + n;
- }
- }
- }
- return first;
-}
-
-// <substitution> ::= S <seq-id> _
-// ::= S_
-// <substitution> ::= Sa # ::std::allocator
-// <substitution> ::= Sb # ::std::basic_string
-// <substitution> ::= Ss # ::std::basic_string < char,
-// ::std::char_traits<char>,
-// ::std::allocator<char> >
-// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
-// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
-// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
-
-template <class C>
-const char*
-parse_substitution(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- if (*first == 'S')
- {
- switch (first[1])
- {
- case 'a':
- db.names.push_back("std::allocator");
- first += 2;
- break;
- case 'b':
- db.names.push_back("std::basic_string");
- first += 2;
- break;
- case 's':
- db.names.push_back("std::string");
- first += 2;
- break;
- case 'i':
- db.names.push_back("std::istream");
- first += 2;
- break;
- case 'o':
- db.names.push_back("std::ostream");
- first += 2;
- break;
- case 'd':
- db.names.push_back("std::iostream");
- first += 2;
- break;
- case '_':
- if (!db.subs.empty())
- {
- for (const auto& n : db.subs.front())
- db.names.push_back(n);
- first += 2;
- }
- break;
- default:
- if (std::isdigit(first[1]) || std::isupper(first[1]))
- {
- size_t sub = 0;
- const char* t = first+1;
- if (std::isdigit(*t))
- sub = static_cast<size_t>(*t - '0');
- else
- sub = static_cast<size_t>(*t - 'A') + 10;
- for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
- {
- sub *= 36;
- if (std::isdigit(*t))
- sub += static_cast<size_t>(*t - '0');
- else
- sub += static_cast<size_t>(*t - 'A') + 10;
- }
- if (t == last || *t != '_')
- return first;
- ++sub;
- if (sub < db.subs.size())
- {
- for (const auto& n : db.subs[sub])
- db.names.push_back(n);
- first = t+1;
- }
- }
- break;
- }
- }
- }
- return first;
-}
-
-// <builtin-type> ::= v # void
-// ::= w # wchar_t
-// ::= b # bool
-// ::= c # char
-// ::= a # signed char
-// ::= h # unsigned char
-// ::= s # short
-// ::= t # unsigned short
-// ::= i # int
-// ::= j # unsigned int
-// ::= l # long
-// ::= m # unsigned long
-// ::= x # long long, __int64
-// ::= y # unsigned long long, __int64
-// ::= n # __int128
-// ::= o # unsigned __int128
-// ::= f # float
-// ::= d # double
-// ::= e # long double, __float80
-// ::= g # __float128
-// ::= z # ellipsis
-// ::= Dd # IEEE 754r decimal floating point (64 bits)
-// ::= De # IEEE 754r decimal floating point (128 bits)
-// ::= Df # IEEE 754r decimal floating point (32 bits)
-// ::= Dh # IEEE 754r half-precision floating point (16 bits)
-// ::= Di # char32_t
-// ::= Ds # char16_t
-// ::= Da # auto (in dependent new-expressions)
-// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
-// ::= u <source-name> # vendor extended type
-
-template <class C>
-const char*
-parse_builtin_type(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- switch (*first)
- {
- case 'v':
- db.names.push_back("void");
- ++first;
- break;
- case 'w':
- db.names.push_back("wchar_t");
- ++first;
- break;
- case 'b':
- db.names.push_back("bool");
- ++first;
- break;
- case 'c':
- db.names.push_back("char");
- ++first;
- break;
- case 'a':
- db.names.push_back("signed char");
- ++first;
- break;
- case 'h':
- db.names.push_back("unsigned char");
- ++first;
- break;
- case 's':
- db.names.push_back("short");
- ++first;
- break;
- case 't':
- db.names.push_back("unsigned short");
- ++first;
- break;
- case 'i':
- db.names.push_back("int");
- ++first;
- break;
- case 'j':
- db.names.push_back("unsigned int");
- ++first;
- break;
- case 'l':
- db.names.push_back("long");
- ++first;
- break;
- case 'm':
- db.names.push_back("unsigned long");
- ++first;
- break;
- case 'x':
- db.names.push_back("long long");
- ++first;
- break;
- case 'y':
- db.names.push_back("unsigned long long");
- ++first;
- break;
- case 'n':
- db.names.push_back("__int128");
- ++first;
- break;
- case 'o':
- db.names.push_back("unsigned __int128");
- ++first;
- break;
- case 'f':
- db.names.push_back("float");
- ++first;
- break;
- case 'd':
- db.names.push_back("double");
- ++first;
- break;
- case 'e':
- db.names.push_back("long double");
- ++first;
- break;
- case 'g':
- db.names.push_back("__float128");
- ++first;
- break;
- case 'z':
- db.names.push_back("...");
- ++first;
- break;
- case 'u':
- {
- const char*t = parse_source_name(first+1, last, db);
- if (t != first+1)
- first = t;
- }
- break;
- case 'D':
- if (first+1 != last)
- {
- switch (first[1])
- {
- case 'd':
- db.names.push_back("decimal64");
- first += 2;
- break;
- case 'e':
- db.names.push_back("decimal128");
- first += 2;
- break;
- case 'f':
- db.names.push_back("decimal32");
- first += 2;
- break;
- case 'h':
- db.names.push_back("decimal16");
- first += 2;
- break;
- case 'i':
- db.names.push_back("char32_t");
- first += 2;
- break;
- case 's':
- db.names.push_back("char16_t");
- first += 2;
- break;
- case 'a':
- db.names.push_back("auto");
- first += 2;
- break;
- case 'n':
- db.names.push_back("std::nullptr_t");
- first += 2;
- break;
- }
- }
- break;
- }
- }
- return first;
-}
-
-// <CV-qualifiers> ::= [r] [V] [K]
-
-const char*
-parse_cv_qualifiers(const char* first, const char* last, unsigned& cv)
-{
- cv = 0;
- if (first != last)
- {
- if (*first == 'r')
- {
- cv |= 4;
- ++first;
- }
- if (*first == 'V')
- {
- cv |= 2;
- ++first;
- }
- if (*first == 'K')
- {
- cv |= 1;
- ++first;
- }
- }
- return first;
-}
-
-// <template-param> ::= T_ # first template parameter
-// ::= T <parameter-2 non-negative number> _
-
-template <class C>
-const char*
-parse_template_param(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- if (*first == 'T')
- {
- if (first[1] == '_')
- {
- if (db.template_param.empty())
- return first;
- if (!db.template_param.back().empty())
- {
- for (auto& t : db.template_param.back().front())
- db.names.push_back(t);
- first += 2;
- }
- else
- {
- db.names.push_back("T_");
- first += 2;
- db.fix_forward_references = true;
- }
- }
- else if (isdigit(first[1]))
- {
- const char* t = first+1;
- size_t sub = static_cast<size_t>(*t - '0');
- for (++t; t != last && isdigit(*t); ++t)
- {
- sub *= 10;
- sub += static_cast<size_t>(*t - '0');
- }
- if (t == last || *t != '_' || db.template_param.empty())
- return first;
- ++sub;
- if (sub < db.template_param.back().size())
- {
- for (auto& temp : db.template_param.back()[sub])
- db.names.push_back(temp);
- first = t+1;
- }
- else
- {
- db.names.push_back(typename C::String(first, t+1));
- first = t+1;
- db.fix_forward_references = true;
- }
- }
- }
- }
- return first;
-}
-
-// cc <type> <expression> # const_cast<type> (expression)
-
-template <class C>
-const char*
-parse_const_cast_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto expr = db.names.back().move_full();
- db.names.pop_back();
- db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
- first = t1;
- }
- }
- }
- return first;
-}
-
-// dc <type> <expression> # dynamic_cast<type> (expression)
-
-template <class C>
-const char*
-parse_dynamic_cast_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto expr = db.names.back().move_full();
- db.names.pop_back();
- db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
- first = t1;
- }
- }
- }
- return first;
-}
-
-// rc <type> <expression> # reinterpret_cast<type> (expression)
-
-template <class C>
-const char*
-parse_reinterpret_cast_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto expr = db.names.back().move_full();
- db.names.pop_back();
- db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";
- first = t1;
- }
- }
- }
- return first;
-}
-
-// sc <type> <expression> # static_cast<type> (expression)
-
-template <class C>
-const char*
-parse_static_cast_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto expr = db.names.back().move_full();
- db.names.pop_back();
- db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
- first = t1;
- }
- }
- }
- return first;
-}
-
-// sp <expression> # pack expansion
-
-template <class C>
-const char*
-parse_pack_expansion(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- return first;
-}
-
-// st <type> # sizeof (a type)
-
-template <class C>
-const char*
-parse_sizeof_type_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 't')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-// sz <expr> # sizeof (a expression)
-
-template <class C>
-const char*
-parse_sizeof_expr_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'z')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-// sZ <template-param> # size of a parameter pack
-
-template <class C>
-const char*
-parse_sizeof_param_pack_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
- {
- size_t k0 = db.names.size();
- const char* t = parse_template_param(first+2, last, db);
- size_t k1 = db.names.size();
- if (t != first+2)
- {
- typename C::String tmp("sizeof...(");
- size_t k = k0;
- if (k != k1)
- {
- tmp += db.names[k].move_full();
- for (++k; k != k1; ++k)
- tmp += ", " + db.names[k].move_full();
- }
- tmp += ")";
- for (; k1 != k0; --k1)
- db.names.pop_back();
- db.names.push_back(std::move(tmp));
- first = t;
- }
- }
- return first;
-}
-
-// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter
-// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
-// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter
-// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
-
-template <class C>
-const char*
-parse_function_param(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && *first == 'f')
- {
- if (first[1] == 'p')
- {
- unsigned cv;
- const char* t = parse_cv_qualifiers(first+2, last, cv);
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
- {
- db.names.push_back("fp" + typename C::String(t, t1));
- first = t1+1;
- }
- }
- else if (first[1] == 'L')
- {
- unsigned cv;
- const char* t0 = parse_number(first+2, last);
- if (t0 != last && *t0 == 'p')
- {
- ++t0;
- const char* t = parse_cv_qualifiers(t0, last, cv);
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
- {
- db.names.push_back("fp" + typename C::String(t, t1));
- first = t1+1;
- }
- }
- }
- }
- return first;
-}
-
-// sZ <function-param> # size of a function parameter pack
-
-template <class C>
-const char*
-parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
- {
- const char* t = parse_function_param(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-// te <expression> # typeid (expression)
-// ti <type> # typeid (type)
-
-template <class C>
-const char*
-parse_typeid_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))
- {
- const char* t;
- if (first[1] == 'e')
- t = parse_expression(first+2, last, db);
- else
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "typeid(" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-// tw <expression> # throw expression
-
-template <class C>
-const char*
-parse_throw_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "throw " + db.names.back().move_full();
- first = t;
- }
- }
- return first;
-}
-
-// ds <expression> <expression> # expr.*expr
-
-template <class C>
-const char*
-parse_dot_star_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto expr = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += ".*" + expr;
- first = t1;
- }
- }
- }
- return first;
-}
-
-// <simple-id> ::= <source-name> [ <template-args> ]
-
-template <class C>
-const char*
-parse_simple_id(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- const char* t = parse_source_name(first, last, db);
- if (t != first)
- {
- const char* t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- }
- first = t1;
- }
- else
- first = t;
- }
- return first;
-}
-
-// <unresolved-type> ::= <template-param>
-// ::= <decltype>
-// ::= <substitution>
-
-template <class C>
-const char*
-parse_unresolved_type(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- const char* t = first;
- switch (*first)
- {
- case 'T':
- {
- size_t k0 = db.names.size();
- t = parse_template_param(first, last, db);
- size_t k1 = db.names.size();
- if (t != first && k1 == k0 + 1)
- {
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- else
- {
- for (; k1 != k0; --k1)
- db.names.pop_back();
- }
- break;
- }
- case 'D':
- t = parse_decltype(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- break;
- case 'S':
- t = parse_substitution(first, last, db);
- if (t != first)
- first = t;
- else
- {
- if (last - first > 2 && first[1] == 't')
- {
- t = parse_unqualified_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "std::");
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- }
- }
- break;
- }
- }
- return first;
-}
-
-// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
-// ::= <simple-id> # e.g., ~A<2*N>
-
-template <class C>
-const char*
-parse_destructor_name(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- const char* t = parse_unresolved_type(first, last, db);
- if (t == first)
- t = parse_simple_id(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "~");
- first = t;
- }
- }
- return first;
-}
-
-// <base-unresolved-name> ::= <simple-id> # unresolved name
-// extension ::= <operator-name> # unresolved operator-function-id
-// extension ::= <operator-name> <template-args> # unresolved operator template-id
-// ::= on <operator-name> # unresolved operator-function-id
-// ::= on <operator-name> <template-args> # unresolved operator template-id
-// ::= dn <destructor-name> # destructor or pseudo-destructor;
-// # e.g. ~X or ~X<N-1>
-
-template <class C>
-const char*
-parse_base_unresolved_name(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
- {
- if (first[0] == 'o')
- {
- const char* t = parse_operator_name(first+2, last, db);
- if (t != first+2)
- {
- first = parse_template_args(t, last, db);
- if (first != t)
- {
- if (db.names.size() < 2)
- return first;
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- }
- }
- }
- else
- {
- const char* t = parse_destructor_name(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- }
- else
- {
- const char* t = parse_simple_id(first, last, db);
- if (t == first)
- {
- t = parse_operator_name(first, last, db);
- if (t != first)
- {
- first = parse_template_args(t, last, db);
- if (first != t)
- {
- if (db.names.size() < 2)
- return first;
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- }
- }
- }
- else
- first = t;
- }
- }
- return first;
-}
-
-// <unresolved-qualifier-level> ::= <simple-id>
-
-template <class C>
-const char*
-parse_unresolved_qualifier_level(const char* first, const char* last, C& db)
-{
- return parse_simple_id(first, last, db);
-}
-
-// <unresolved-name>
-// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
-// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
-// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
-// # A::x, N::y, A<T>::z; "gs" means leading "::"
-// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
-// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
-// # T::N::x /decltype(p)::N::x
-// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
-
-template <class C>
-const char*
-parse_unresolved_name(const char* first, const char* last, C& db)
-{
- if (last - first > 2)
- {
- const char* t = first;
- bool global = false;
- if (t[0] == 'g' && t[1] == 's')
- {
- global = true;
- t += 2;
- }
- const char* t2 = parse_base_unresolved_name(t, last, db);
- if (t2 != t)
- {
- if (global)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "::");
- }
- first = t2;
- }
- else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
- {
- if (t[2] == 'N')
- {
- t += 3;
- const char* t1 = parse_unresolved_type(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- t = t1;
- if (t == last)
- {
- db.names.pop_back();
- return first;
- }
- }
- while (*t != 'E')
- {
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last || db.names.size() < 2)
- return first;
- auto s = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "::" + std::move(s);
- t = t1;
- }
- ++t;
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
- {
- if (!db.names.empty())
- db.names.pop_back();
- return first;
- }
- if (db.names.size() < 2)
- return first;
- auto s = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "::" + std::move(s);
- first = t1;
- }
- else
- {
- t += 2;
- const char* t1 = parse_unresolved_type(t, last, db);
- if (t1 != t)
- {
- t = t1;
- t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- t = t1;
- }
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
- {
- if (!db.names.empty())
- db.names.pop_back();
- return first;
- }
- if (db.names.size() < 2)
- return first;
- auto s = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "::" + std::move(s);
- first = t1;
- }
- else
- {
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- if (global)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "::");
- }
- while (*t != 'E')
- {
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last || db.names.size() < 2)
- return first;
- auto s = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "::" + std::move(s);
- t = t1;
- }
- ++t;
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
- {
- if (!db.names.empty())
- db.names.pop_back();
- return first;
- }
- if (db.names.size() < 2)
- return first;
- auto s = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "::" + std::move(s);
- first = t1;
- }
- }
- }
- }
- return first;
-}
-
-// dt <expression> <unresolved-name> # expr.name
-
-template <class C>
-const char*
-parse_dot_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_unresolved_name(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto name = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "." + name;
- first = t1;
- }
- }
- }
- return first;
-}
-
-// cl <expression>+ E # call
-
-template <class C>
-const char*
-parse_call_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- if (t == last)
- return first;
- if (db.names.empty())
- return first;
- db.names.back().first += db.names.back().second;
- db.names.back().second = typename C::String();
- db.names.back().first.append("(");
- bool first_expr = true;
- while (*t != 'E')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- if (db.names.empty())
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- if (!tmp.empty())
- {
- if (db.names.empty())
- return first;
- if (!first_expr)
- {
- db.names.back().first.append(", ");
- first_expr = false;
- }
- db.names.back().first.append(tmp);
- }
- t = t1;
- }
- ++t;
- if (db.names.empty())
- return first;
- db.names.back().first.append(")");
- first = t;
- }
- }
- return first;
-}
-
-// [gs] nw <expression>* _ <type> E # new (expr-list) type
-// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
-// [gs] na <expression>* _ <type> E # new[] (expr-list) type
-// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
-// <initializer> ::= pi <expression>* E # parenthesized initialization
-
-template <class C>
-const char*
-parse_new_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 4)
- {
- const char* t = first;
- bool parsed_gs = false;
- if (t[0] == 'g' && t[1] == 's')
- {
- t += 2;
- parsed_gs = true;
- }
- if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a'))
- {
- bool is_array = t[1] == 'a';
- t += 2;
- if (t == last)
- return first;
- bool has_expr_list = false;
- bool first_expr = true;
- while (*t != '_')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- has_expr_list = true;
- if (!first_expr)
- {
- if (db.names.empty())
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- if (!tmp.empty())
- {
- if (db.names.empty())
- return first;
- db.names.back().first.append(", ");
- db.names.back().first.append(tmp);
- first_expr = false;
- }
- }
- t = t1;
- }
- ++t;
- const char* t1 = parse_type(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- bool has_init = false;
- if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')
- {
- t += 2;
- has_init = true;
- first_expr = true;
- while (*t != 'E')
- {
- t1 = parse_expression(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- if (!first_expr)
- {
- if (db.names.empty())
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- if (!tmp.empty())
- {
- if (db.names.empty())
- return first;
- db.names.back().first.append(", ");
- db.names.back().first.append(tmp);
- first_expr = false;
- }
- }
- t = t1;
- }
- }
- if (*t != 'E')
- return first;
- typename C::String init_list;
- if (has_init)
- {
- if (db.names.empty())
- return first;
- init_list = db.names.back().move_full();
- db.names.pop_back();
- }
- if (db.names.empty())
- return first;
- auto type = db.names.back().move_full();
- db.names.pop_back();
- typename C::String expr_list;
- if (has_expr_list)
- {
- if (db.names.empty())
- return first;
- expr_list = db.names.back().move_full();
- db.names.pop_back();
- }
- typename C::String r;
- if (parsed_gs)
- r = "::";
- if (is_array)
- r += "[] ";
- else
- r += " ";
- if (has_expr_list)
- r += "(" + expr_list + ") ";
- r += type;
- if (has_init)
- r += " (" + init_list + ")";
- db.names.push_back(std::move(r));
- first = t+1;
- }
- }
- return first;
-}
-
-// cv <type> <expression> # conversion with one argument
-// cv <type> _ <expression>* E # conversion with a different number of arguments
-
-template <class C>
-const char*
-parse_conversion_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
- {
- bool try_to_parse_template_args = db.try_to_parse_template_args;
- db.try_to_parse_template_args = false;
- const char* t = parse_type(first+2, last, db);
- db.try_to_parse_template_args = try_to_parse_template_args;
- if (t != first+2 && t != last)
- {
- if (*t != '_')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == t)
- return first;
- t = t1;
- }
- else
- {
- ++t;
- if (t == last)
- return first;
- if (*t == 'E')
- db.names.emplace_back();
- else
- {
- bool first_expr = true;
- while (*t != 'E')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- if (!first_expr)
- {
- if (db.names.empty())
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- if (!tmp.empty())
- {
- if (db.names.empty())
- return first;
- db.names.back().first.append(", ");
- db.names.back().first.append(tmp);
- first_expr = false;
- }
- }
- t = t1;
- }
- }
- ++t;
- }
- if (db.names.size() < 2)
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
- first = t;
- }
- }
- return first;
-}
-
-// pt <expression> <expression> # expr->name
-
-template <class C>
-const char*
-parse_arrow_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "->";
- db.names.back().first += tmp;
- first = t1;
- }
- }
- }
- return first;
-}
-
-// <ref-qualifier> ::= R # & ref-qualifier
-// <ref-qualifier> ::= O # && ref-qualifier
-
-// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
-
-template <class C>
-const char*
-parse_function_type(const char* first, const char* last, C& db)
-{
- if (first != last && *first == 'F')
- {
- const char* t = first+1;
- if (t != last)
- {
- bool externC = false;
- if (*t == 'Y')
- {
- externC = true;
- if (++t == last)
- return first;
- }
- const char* t1 = parse_type(t, last, db);
- if (t1 != t)
- {
- t = t1;
- typename C::String sig("(");
- int ref_qual = 0;
- while (true)
- {
- if (t == last)
- {
- db.names.pop_back();
- return first;
- }
- if (*t == 'E')
- {
- ++t;
- break;
- }
- if (*t == 'v')
- {
- ++t;
- continue;
- }
- if (*t == 'R' && t+1 != last && t[1] == 'E')
- {
- ref_qual = 1;
- ++t;
- continue;
- }
- if (*t == 'O' && t+1 != last && t[1] == 'E')
- {
- ref_qual = 2;
- ++t;
- continue;
- }
- size_t k0 = db.names.size();
- t1 = parse_type(t, last, db);
- size_t k1 = db.names.size();
- if (t1 == t || t1 == last)
- return first;
- for (size_t k = k0; k < k1; ++k)
- {
- if (sig.size() > 1)
- sig += ", ";
- sig += db.names[k].move_full();
- }
- for (size_t k = k0; k < k1; ++k)
- db.names.pop_back();
- t = t1;
- }
- sig += ")";
- switch (ref_qual)
- {
- case 1:
- sig += " &";
- break;
- case 2:
- sig += " &&";
- break;
- }
- if (db.names.empty())
- return first;
- db.names.back().first += " ";
- db.names.back().second.insert(0, sig);
- first = t;
- }
- }
- }
- return first;
-}
-
-// <pointer-to-member-type> ::= M <class type> <member type>
-
-template <class C>
-const char*
-parse_pointer_to_member_type(const char* first, const char* last, C& db)
-{
- if (first != last && *first == 'M')
- {
- const char* t = parse_type(first+1, last, db);
- if (t != first+1)
- {
- const char* t2 = parse_type(t, last, db);
- if (t2 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto func = std::move(db.names.back());
- db.names.pop_back();
- auto class_type = std::move(db.names.back());
- if (func.second.front() == '(')
- {
- db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*";
- db.names.back().second = ")" + std::move(func.second);
- }
- else
- {
- db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*";
- db.names.back().second = std::move(func.second);
- }
- first = t2;
- }
- }
- }
- return first;
-}
-
-// <array-type> ::= A <positive dimension number> _ <element type>
-// ::= A [<dimension expression>] _ <element type>
-
-template <class C>
-const char*
-parse_array_type(const char* first, const char* last, C& db)
-{
- if (first != last && *first == 'A' && first+1 != last)
- {
- if (first[1] == '_')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- if (db.names.back().second.substr(0, 2) == " [")
- db.names.back().second.erase(0, 1);
- db.names.back().second.insert(0, " []");
- first = t;
- }
- }
- else if ('1' <= first[1] && first[1] <= '9')
- {
- const char* t = parse_number(first+1, last);
- if (t != last && *t == '_')
- {
- const char* t2 = parse_type(t+1, last, db);
- if (t2 != t+1)
- {
- if (db.names.empty())
- return first;
- if (db.names.back().second.substr(0, 2) == " [")
- db.names.back().second.erase(0, 1);
- db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]");
- first = t2;
- }
- }
- }
- else
- {
- const char* t = parse_expression(first+1, last, db);
- if (t != first+1 && t != last && *t == '_')
- {
- const char* t2 = parse_type(++t, last, db);
- if (t2 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto type = std::move(db.names.back());
- db.names.pop_back();
- auto expr = std::move(db.names.back());
- db.names.back().first = std::move(type.first);
- if (type.second.substr(0, 2) == " [")
- type.second.erase(0, 1);
- db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second);
- first = t2;
- }
- }
- }
- }
- return first;
-}
-
-// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
-// ::= DT <expression> E # decltype of an expression (C++0x)
-
-template <class C>
-const char*
-parse_decltype(const char* first, const char* last, C& db)
-{
- if (last - first >= 4 && first[0] == 'D')
- {
- switch (first[1])
- {
- case 't':
- case 'T':
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (db.names.empty())
- return first;
- db.names.back() = "decltype(" + db.names.back().move_full() + ")";
- first = t+1;
- }
- }
- break;
- }
- }
- return first;
-}
-
-// extension:
-// <vector-type> ::= Dv <positive dimension number> _
-// <extended element type>
-// ::= Dv [<dimension expression>] _ <element type>
-// <extended element type> ::= <element type>
-// ::= p # AltiVec vector pixel
-
-template <class C>
-const char*
-parse_vector_type(const char* first, const char* last, C& db)
-{
- if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
- {
- if ('1' <= first[2] && first[2] <= '9')
- {
- const char* t = parse_number(first+2, last);
- if (t == last || *t != '_')
- return first;
- const char* num = first + 2;
- size_t sz = static_cast<size_t>(t - num);
- if (++t != last)
- {
- if (*t != 'p')
- {
- const char* t1 = parse_type(t, last, db);
- if (t1 != t)
- {
- if (db.names.empty())
- return first;
- db.names.back().first += " vector[" + typename C::String(num, sz) + "]";
- first = t1;
- }
- }
- else
- {
- ++t;
- db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]");
- first = t;
- }
- }
- }
- else
- {
- typename C::String num;
- const char* t1 = first+2;
- if (*t1 != '_')
- {
- const char* t = parse_expression(t1, last, db);
- if (t != t1)
- {
- if (db.names.empty())
- return first;
- num = db.names.back().move_full();
- db.names.pop_back();
- t1 = t;
- }
- }
- if (t1 != last && *t1 == '_' && ++t1 != last)
- {
- const char* t = parse_type(t1, last, db);
- if (t != t1)
- {
- if (db.names.empty())
- return first;
- db.names.back().first += " vector[" + num + "]";
- first = t;
- }
- }
- }
- }
- return first;
-}
-
-// <type> ::= <builtin-type>
-// ::= <function-type>
-// ::= <class-enum-type>
-// ::= <array-type>
-// ::= <pointer-to-member-type>
-// ::= <template-param>
-// ::= <template-template-param> <template-args>
-// ::= <decltype>
-// ::= <substitution>
-// ::= <CV-qualifiers> <type>
-// ::= P <type> # pointer-to
-// ::= R <type> # reference-to
-// ::= O <type> # rvalue reference-to (C++0x)
-// ::= C <type> # complex pair (C 2000)
-// ::= G <type> # imaginary (C 2000)
-// ::= Dp <type> # pack expansion (C++0x)
-// ::= U <source-name> <type> # vendor extended type qualifier
-// extension := U <objc-name> <objc-type> # objc-type<identifier>
-// extension := <vector-type> # <vector-type> starts with Dv
-
-// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
-// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
-
-template <class C>
-const char*
-parse_type(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- switch (*first)
- {
- case 'r':
- case 'V':
- case 'K':
- {
- unsigned cv = 0;
- const char* t = parse_cv_qualifiers(first, last, cv);
- if (t != first)
- {
- bool is_function = *t == 'F';
- size_t k0 = db.names.size();
- const char* t1 = parse_type(t, last, db);
- size_t k1 = db.names.size();
- if (t1 != t)
- {
- if (is_function)
- db.subs.pop_back();
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- {
- if (is_function)
- {
- size_t p = db.names[k].second.size();
- if (db.names[k].second[p-2] == '&')
- p -= 3;
- else if (db.names[k].second.back() == '&')
- p -= 2;
- if (cv & 1)
- {
- db.names[k].second.insert(p, " const");
- p += 6;
- }
- if (cv & 2)
- {
- db.names[k].second.insert(p, " volatile");
- p += 9;
- }
- if (cv & 4)
- db.names[k].second.insert(p, " restrict");
- }
- else
- {
- if (cv & 1)
- db.names[k].first.append(" const");
- if (cv & 2)
- db.names[k].first.append(" volatile");
- if (cv & 4)
- db.names[k].first.append(" restrict");
- }
- db.subs.back().push_back(db.names[k]);
- }
- first = t1;
- }
- }
- }
- break;
- default:
- {
- const char* t = parse_builtin_type(first, last, db);
- if (t != first)
- {
- first = t;
- }
- else
- {
- switch (*first)
- {
- case 'A':
- t = parse_array_type(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- first = t;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- break;
- case 'C':
- t = parse_type(first+1, last, db);
- if (t != first+1)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.append(" complex");
- first = t;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- break;
- case 'F':
- t = parse_function_type(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- first = t;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- break;
- case 'G':
- t = parse_type(first+1, last, db);
- if (t != first+1)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.append(" imaginary");
- first = t;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- break;
- case 'M':
- t = parse_pointer_to_member_type(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- first = t;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- break;
- case 'O':
- {
- size_t k0 = db.names.size();
- t = parse_type(first+1, last, db);
- size_t k1 = db.names.size();
- if (t != first+1)
- {
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- {
- if (db.names[k].second.substr(0, 2) == " [")
- {
- db.names[k].first += " (";
- db.names[k].second.insert(0, ")");
- }
- else if (db.names[k].second.front() == '(')
- {
- db.names[k].first += "(";
- db.names[k].second.insert(0, ")");
- }
- db.names[k].first.append("&&");
- db.subs.back().push_back(db.names[k]);
- }
- first = t;
- }
- break;
- }
- case 'P':
- {
- size_t k0 = db.names.size();
- t = parse_type(first+1, last, db);
- size_t k1 = db.names.size();
- if (t != first+1)
- {
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- {
- if (db.names[k].second.substr(0, 2) == " [")
- {
- db.names[k].first += " (";
- db.names[k].second.insert(0, ")");
- }
- else if (db.names[k].second.front() == '(')
- {
- db.names[k].first += "(";
- db.names[k].second.insert(0, ")");
- }
- if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<")
- {
- db.names[k].first.append("*");
- }
- else
- {
- db.names[k].first.replace(0, 11, "id");
- }
- db.subs.back().push_back(db.names[k]);
- }
- first = t;
- }
- break;
- }
- case 'R':
- {
- size_t k0 = db.names.size();
- t = parse_type(first+1, last, db);
- size_t k1 = db.names.size();
- if (t != first+1)
- {
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- {
- if (db.names[k].second.substr(0, 2) == " [")
- {
- db.names[k].first += " (";
- db.names[k].second.insert(0, ")");
- }
- else if (db.names[k].second.front() == '(')
- {
- db.names[k].first += "(";
- db.names[k].second.insert(0, ")");
- }
- db.names[k].first.append("&");
- db.subs.back().push_back(db.names[k]);
- }
- first = t;
- }
- break;
- }
- case 'T':
- {
- size_t k0 = db.names.size();
- t = parse_template_param(first, last, db);
- size_t k1 = db.names.size();
- if (t != first)
- {
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- db.subs.back().push_back(db.names[k]);
- if (db.try_to_parse_template_args && k1 == k0+1)
- {
- const char* t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- t = t1;
- }
- }
- first = t;
- }
- break;
- }
- case 'U':
- if (first+1 != last)
- {
- t = parse_source_name(first+1, last, db);
- if (t != first+1)
- {
- const char* t2 = parse_type(t, last, db);
- if (t2 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto type = db.names.back().move_full();
- db.names.pop_back();
- if (db.names.back().first.substr(0, 9) != "objcproto")
- {
- db.names.back() = type + " " + db.names.back().move_full();
- }
- else
- {
- auto proto = db.names.back().move_full();
- db.names.pop_back();
- t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db);
- if (t != proto.data() + 9)
- {
- db.names.back() = type + "<" + db.names.back().move_full() + ">";
- }
- else
- {
- db.names.push_back(type + " " + proto);
- }
- }
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t2;
- }
- }
- }
- break;
- case 'S':
- if (first+1 != last && first[1] == 't')
- {
- t = parse_name(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- }
- else
- {
- t = parse_substitution(first, last, db);
- if (t != first)
- {
- first = t;
- // Parsed a substitution. If the substitution is a
- // <template-param> it might be followed by <template-args>.
- t = parse_template_args(first, last, db);
- if (t != first)
- {
- if (db.names.size() < 2)
- return first;
- auto template_args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += template_args;
- // Need to create substitution for <template-template-param> <template-args>
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- }
- }
- break;
- case 'D':
- if (first+1 != last)
- {
- switch (first[1])
- {
- case 'p':
- {
- size_t k0 = db.names.size();
- t = parse_type(first+2, last, db);
- size_t k1 = db.names.size();
- if (t != first+2)
- {
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- db.subs.back().push_back(db.names[k]);
- first = t;
- return first;
- }
- break;
- }
- case 't':
- case 'T':
- t = parse_decltype(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- return first;
- }
- break;
- case 'v':
- t = parse_vector_type(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- return first;
- }
- break;
- }
- }
- // drop through
- default:
- // must check for builtin-types before class-enum-types to avoid
- // ambiguities with operator-names
- t = parse_builtin_type(first, last, db);
- if (t != first)
- {
- first = t;
- }
- else
- {
- t = parse_name(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- }
- break;
- }
- }
- break;
- }
- }
- }
- return first;
-}
-
-// <operator-name>
-// ::= aa # &&
-// ::= ad # & (unary)
-// ::= an # &
-// ::= aN # &=
-// ::= aS # =
-// ::= cl # ()
-// ::= cm # ,
-// ::= co # ~
-// ::= cv <type> # (cast)
-// ::= da # delete[]
-// ::= de # * (unary)
-// ::= dl # delete
-// ::= dv # /
-// ::= dV # /=
-// ::= eo # ^
-// ::= eO # ^=
-// ::= eq # ==
-// ::= ge # >=
-// ::= gt # >
-// ::= ix # []
-// ::= le # <=
-// ::= li <source-name> # operator ""
-// ::= ls # <<
-// ::= lS # <<=
-// ::= lt # <
-// ::= mi # -
-// ::= mI # -=
-// ::= ml # *
-// ::= mL # *=
-// ::= mm # -- (postfix in <expression> context)
-// ::= na # new[]
-// ::= ne # !=
-// ::= ng # - (unary)
-// ::= nt # !
-// ::= nw # new
-// ::= oo # ||
-// ::= or # |
-// ::= oR # |=
-// ::= pm # ->*
-// ::= pl # +
-// ::= pL # +=
-// ::= pp # ++ (postfix in <expression> context)
-// ::= ps # + (unary)
-// ::= pt # ->
-// ::= qu # ?
-// ::= rm # %
-// ::= rM # %=
-// ::= rs # >>
-// ::= rS # >>=
-// ::= v <digit> <source-name> # vendor extended operator
-
-template <class C>
-const char*
-parse_operator_name(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- switch (first[0])
- {
- case 'a':
- switch (first[1])
- {
- case 'a':
- db.names.push_back("operator&&");
- first += 2;
- break;
- case 'd':
- case 'n':
- db.names.push_back("operator&");
- first += 2;
- break;
- case 'N':
- db.names.push_back("operator&=");
- first += 2;
- break;
- case 'S':
- db.names.push_back("operator=");
- first += 2;
- break;
- }
- break;
- case 'c':
- switch (first[1])
- {
- case 'l':
- db.names.push_back("operator()");
- first += 2;
- break;
- case 'm':
- db.names.push_back("operator,");
- first += 2;
- break;
- case 'o':
- db.names.push_back("operator~");
- first += 2;
- break;
- case 'v':
- {
- bool try_to_parse_template_args = db.try_to_parse_template_args;
- db.try_to_parse_template_args = false;
- const char* t = parse_type(first+2, last, db);
- db.try_to_parse_template_args = try_to_parse_template_args;
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "operator ");
- db.parsed_ctor_dtor_cv = true;
- first = t;
- }
- }
- break;
- }
- break;
- case 'd':
- switch (first[1])
- {
- case 'a':
- db.names.push_back("operator delete[]");
- first += 2;
- break;
- case 'e':
- db.names.push_back("operator*");
- first += 2;
- break;
- case 'l':
- db.names.push_back("operator delete");
- first += 2;
- break;
- case 'v':
- db.names.push_back("operator/");
- first += 2;
- break;
- case 'V':
- db.names.push_back("operator/=");
- first += 2;
- break;
- }
- break;
- case 'e':
- switch (first[1])
- {
- case 'o':
- db.names.push_back("operator^");
- first += 2;
- break;
- case 'O':
- db.names.push_back("operator^=");
- first += 2;
- break;
- case 'q':
- db.names.push_back("operator==");
- first += 2;
- break;
- }
- break;
- case 'g':
- switch (first[1])
- {
- case 'e':
- db.names.push_back("operator>=");
- first += 2;
- break;
- case 't':
- db.names.push_back("operator>");
- first += 2;
- break;
- }
- break;
- case 'i':
- if (first[1] == 'x')
- {
- db.names.push_back("operator[]");
- first += 2;
- }
- break;
- case 'l':
- switch (first[1])
- {
- case 'e':
- db.names.push_back("operator<=");
- first += 2;
- break;
- case 'i':
- {
- const char* t = parse_source_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "operator\"\" ");
- first = t;
- }
- }
- break;
- case 's':
- db.names.push_back("operator<<");
- first += 2;
- break;
- case 'S':
- db.names.push_back("operator<<=");
- first += 2;
- break;
- case 't':
- db.names.push_back("operator<");
- first += 2;
- break;
- }
- break;
- case 'm':
- switch (first[1])
- {
- case 'i':
- db.names.push_back("operator-");
- first += 2;
- break;
- case 'I':
- db.names.push_back("operator-=");
- first += 2;
- break;
- case 'l':
- db.names.push_back("operator*");
- first += 2;
- break;
- case 'L':
- db.names.push_back("operator*=");
- first += 2;
- break;
- case 'm':
- db.names.push_back("operator--");
- first += 2;
- break;
- }
- break;
- case 'n':
- switch (first[1])
- {
- case 'a':
- db.names.push_back("operator new[]");
- first += 2;
- break;
- case 'e':
- db.names.push_back("operator!=");
- first += 2;
- break;
- case 'g':
- db.names.push_back("operator-");
- first += 2;
- break;
- case 't':
- db.names.push_back("operator!");
- first += 2;
- break;
- case 'w':
- db.names.push_back("operator new");
- first += 2;
- break;
- }
- break;
- case 'o':
- switch (first[1])
- {
- case 'o':
- db.names.push_back("operator||");
- first += 2;
- break;
- case 'r':
- db.names.push_back("operator|");
- first += 2;
- break;
- case 'R':
- db.names.push_back("operator|=");
- first += 2;
- break;
- }
- break;
- case 'p':
- switch (first[1])
- {
- case 'm':
- db.names.push_back("operator->*");
- first += 2;
- break;
- case 'l':
- db.names.push_back("operator+");
- first += 2;
- break;
- case 'L':
- db.names.push_back("operator+=");
- first += 2;
- break;
- case 'p':
- db.names.push_back("operator++");
- first += 2;
- break;
- case 's':
- db.names.push_back("operator+");
- first += 2;
- break;
- case 't':
- db.names.push_back("operator->");
- first += 2;
- break;
- }
- break;
- case 'q':
- if (first[1] == 'u')
- {
- db.names.push_back("operator?");
- first += 2;
- }
- break;
- case 'r':
- switch (first[1])
- {
- case 'm':
- db.names.push_back("operator%");
- first += 2;
- break;
- case 'M':
- db.names.push_back("operator%=");
- first += 2;
- break;
- case 's':
- db.names.push_back("operator>>");
- first += 2;
- break;
- case 'S':
- db.names.push_back("operator>>=");
- first += 2;
- break;
- }
- break;
- case 'v':
- if (std::isdigit(first[1]))
- {
- const char* t = parse_source_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "operator ");
- first = t;
- }
- }
- break;
- }
- }
- return first;
-}
-
-template <class C>
-const char*
-parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db)
-{
- const char* t = parse_number(first, last);
- if (t != first && t != last && *t == 'E')
- {
- if (lit.size() > 3)
- db.names.push_back("(" + lit + ")");
- else
- db.names.emplace_back();
- if (*first == 'n')
- {
- db.names.back().first += '-';
- ++first;
- }
- db.names.back().first.append(first, t);
- if (lit.size() <= 3)
- db.names.back().first += lit;
- first = t+1;
- }
- return first;
-}
-
-// <expr-primary> ::= L <type> <value number> E # integer literal
-// ::= L <type> <value float> E # floating literal
-// ::= L <string type> E # string literal
-// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
-// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
-// ::= L <mangled-name> E # external name
-
-template <class C>
-const char*
-parse_expr_primary(const char* first, const char* last, C& db)
-{
- if (last - first >= 4 && *first == 'L')
- {
- switch (first[1])
- {
- case 'w':
- {
- const char* t = parse_integer_literal(first+2, last, "wchar_t", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'b':
- if (first[3] == 'E')
- {
- switch (first[2])
- {
- case '0':
- db.names.push_back("false");
- first += 4;
- break;
- case '1':
- db.names.push_back("true");
- first += 4;
- break;
- }
- }
- break;
- case 'c':
- {
- const char* t = parse_integer_literal(first+2, last, "char", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'a':
- {
- const char* t = parse_integer_literal(first+2, last, "signed char", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'h':
- {
- const char* t = parse_integer_literal(first+2, last, "unsigned char", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 's':
- {
- const char* t = parse_integer_literal(first+2, last, "short", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 't':
- {
- const char* t = parse_integer_literal(first+2, last, "unsigned short", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'i':
- {
- const char* t = parse_integer_literal(first+2, last, "", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'j':
- {
- const char* t = parse_integer_literal(first+2, last, "u", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'l':
- {
- const char* t = parse_integer_literal(first+2, last, "l", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'm':
- {
- const char* t = parse_integer_literal(first+2, last, "ul", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'x':
- {
- const char* t = parse_integer_literal(first+2, last, "ll", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'y':
- {
- const char* t = parse_integer_literal(first+2, last, "ull", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'n':
- {
- const char* t = parse_integer_literal(first+2, last, "__int128", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'o':
- {
- const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'f':
- {
- const char* t = parse_floating_number<float>(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'd':
- {
- const char* t = parse_floating_number<double>(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'e':
- {
- const char* t = parse_floating_number<long double>(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- break;
- case '_':
- if (first[2] == 'Z')
- {
- const char* t = parse_encoding(first+3, last, db);
- if (t != first+3 && t != last && *t == 'E')
- first = t+1;
- }
- break;
- case 'T':
- // Invalid mangled name per
- // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
- break;
- default:
- {
- // might be named type
- const char* t = parse_type(first+1, last, db);
- if (t != first+1 && t != last)
- {
- if (*t != 'E')
- {
- const char* n = t;
- for (; n != last && isdigit(*n); ++n)
- ;
- if (n != t && n != last && *n == 'E')
- {
- if (db.names.empty())
- return first;
- db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n);
- first = n+1;
- break;
- }
- }
- else
- {
- first = t+1;
- break;
- }
- }
- }
- }
- }
- return first;
-}
-
-template <class String>
-String
-base_name(String& s)
-{
- if (s.empty())
- return s;
- if (s == "std::string")
- {
- s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >";
- return "basic_string";
- }
- if (s == "std::istream")
- {
- s = "std::basic_istream<char, std::char_traits<char> >";
- return "basic_istream";
- }
- if (s == "std::ostream")
- {
- s = "std::basic_ostream<char, std::char_traits<char> >";
- return "basic_ostream";
- }
- if (s == "std::iostream")
- {
- s = "std::basic_iostream<char, std::char_traits<char> >";
- return "basic_iostream";
- }
- const char* const pf = s.data();
- const char* pe = pf + s.size();
- if (pe[-1] == '>')
- {
- unsigned c = 1;
- while (true)
- {
- if (--pe == pf)
- return String();
- if (pe[-1] == '<')
- {
- if (--c == 0)
- {
- --pe;
- break;
- }
- }
- else if (pe[-1] == '>')
- ++c;
- }
- }
- const char* p0 = pe - 1;
- for (; p0 != pf; --p0)
- {
- if (*p0 == ':')
- {
- ++p0;
- break;
- }
- }
- return String(p0, pe);
-}
-
-// <ctor-dtor-name> ::= C1 # complete object constructor
-// ::= C2 # base object constructor
-// ::= C3 # complete object allocating constructor
-// extension ::= C5 # ?
-// ::= D0 # deleting destructor
-// ::= D1 # complete object destructor
-// ::= D2 # base object destructor
-// extension ::= D5 # ?
-
-template <class C>
-const char*
-parse_ctor_dtor_name(const char* first, const char* last, C& db)
-{
- if (last-first >= 2 && !db.names.empty())
- {
- switch (first[0])
- {
- case 'C':
- switch (first[1])
- {
- case '1':
- case '2':
- case '3':
- case '5':
- if (db.names.empty())
- return first;
- db.names.push_back(base_name(db.names.back().first));
- first += 2;
- db.parsed_ctor_dtor_cv = true;
- break;
- }
- break;
- case 'D':
- switch (first[1])
- {
- case '0':
- case '1':
- case '2':
- case '5':
- if (db.names.empty())
- return first;
- db.names.push_back("~" + base_name(db.names.back().first));
- first += 2;
- db.parsed_ctor_dtor_cv = true;
- break;
- }
- break;
- }
- }
- return first;
-}
-
-// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
-// ::= <closure-type-name>
-//
-// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
-//
-// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
-
-template <class C>
-const char*
-parse_unnamed_type_name(const char* first, const char* last, C& db)
-{
- if (last - first > 2 && first[0] == 'U')
- {
- char type = first[1];
- switch (type)
- {
- case 't':
- {
- db.names.push_back(typename C::String("'unnamed"));
- const char* t0 = first+2;
- if (t0 == last)
- {
- db.names.pop_back();
- return first;
- }
- if (std::isdigit(*t0))
- {
- const char* t1 = t0 + 1;
- while (t1 != last && std::isdigit(*t1))
- ++t1;
- db.names.back().first.append(t0, t1);
- t0 = t1;
- }
- db.names.back().first.push_back('\'');
- if (t0 == last || *t0 != '_')
- {
- db.names.pop_back();
- return first;
- }
- first = t0 + 1;
- }
- break;
- case 'l':
- {
- db.names.push_back(typename C::String("'lambda'("));
- const char* t0 = first+2;
- if (first[2] == 'v')
- {
- db.names.back().first += ')';
- ++t0;
- }
- else
- {
- const char* t1 = parse_type(t0, last, db);
- if (t1 == t0)
- {
- db.names.pop_back();
- return first;
- }
- if (db.names.size() < 2)
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first.append(tmp);
- t0 = t1;
- while (true)
- {
- t1 = parse_type(t0, last, db);
- if (t1 == t0)
- break;
- if (db.names.size() < 2)
- return first;
- tmp = db.names.back().move_full();
- db.names.pop_back();
- if (!tmp.empty())
- {
- db.names.back().first.append(", ");
- db.names.back().first.append(tmp);
- }
- t0 = t1;
- }
- db.names.back().first.append(")");
- }
- if (t0 == last || *t0 != 'E')
- {
- db.names.pop_back();
- return first;
- }
- ++t0;
- if (t0 == last)
- {
- db.names.pop_back();
- return first;
- }
- if (std::isdigit(*t0))
- {
- const char* t1 = t0 + 1;
- while (t1 != last && std::isdigit(*t1))
- ++t1;
- db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1);
- t0 = t1;
- }
- if (t0 == last || *t0 != '_')
- {
- db.names.pop_back();
- return first;
- }
- first = t0 + 1;
- }
- break;
- }
- }
- return first;
-}
-
-// <unqualified-name> ::= <operator-name>
-// ::= <ctor-dtor-name>
-// ::= <source-name>
-// ::= <unnamed-type-name>
-
-template <class C>
-const char*
-parse_unqualified_name(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- const char* t;
- switch (*first)
- {
- case 'C':
- case 'D':
- t = parse_ctor_dtor_name(first, last, db);
- if (t != first)
- first = t;
- break;
- case 'U':
- t = parse_unnamed_type_name(first, last, db);
- if (t != first)
- first = t;
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- t = parse_source_name(first, last, db);
- if (t != first)
- first = t;
- break;
- default:
- t = parse_operator_name(first, last, db);
- if (t != first)
- first = t;
- break;
- };
- }
- return first;
-}
-
-// <unscoped-name> ::= <unqualified-name>
-// ::= St <unqualified-name> # ::std::
-// extension ::= StL<unqualified-name>
-
-template <class C>
-const char*
-parse_unscoped_name(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- const char* t0 = first;
- bool St = false;
- if (first[0] == 'S' && first[1] == 't')
- {
- t0 += 2;
- St = true;
- if (t0 != last && *t0 == 'L')
- ++t0;
- }
- const char* t1 = parse_unqualified_name(t0, last, db);
- if (t1 != t0)
- {
- if (St)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "std::");
- }
- first = t1;
- }
- }
- return first;
-}
-
-// at <type> # alignof (a type)
-
-template <class C>
-const char*
-parse_alignof_type(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-// az <expression> # alignof (a expression)
-
-template <class C>
-const char*
-parse_alignof_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'a' && first[1] == 'z')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-template <class C>
-const char*
-parse_noexcept_expression(const char* first, const char* last, C& db)
-{
- const char* t1 = parse_expression(first, last, db);
- if (t1 != first)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = "noexcept (" + db.names.back().move_full() + ")";
- first = t1;
- }
- return first;
-}
-
-template <class C>
-const char*
-parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db)
-{
- const char* t1 = parse_expression(first, last, db);
- if (t1 != first)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = op + "(" + db.names.back().move_full() + ")";
- first = t1;
- }
- return first;
-}
-
-template <class C>
-const char*
-parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db)
-{
- const char* t1 = parse_expression(first, last, db);
- if (t1 != first)
- {
- const char* t2 = parse_expression(t1, last, db);
- if (t2 != t1)
- {
- if (db.names.size() < 2)
- return first;
- auto op2 = db.names.back().move_full();
- db.names.pop_back();
- auto op1 = db.names.back().move_full();
- auto& nm = db.names.back().first;
- nm.clear();
- if (op == ">")
- nm += '(';
- nm += "(" + op1 + ") " + op + " (" + op2 + ")";
- if (op == ">")
- nm += ')';
- first = t2;
- }
- else
- db.names.pop_back();
- }
- return first;
-}
-
-// <expression> ::= <unary operator-name> <expression>
-// ::= <binary operator-name> <expression> <expression>
-// ::= <ternary operator-name> <expression> <expression> <expression>
-// ::= cl <expression>+ E # call
-// ::= cv <type> <expression> # conversion with one argument
-// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
-// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
-// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
-// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
-// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
-// ::= [gs] dl <expression> # delete expression
-// ::= [gs] da <expression> # delete[] expression
-// ::= pp_ <expression> # prefix ++
-// ::= mm_ <expression> # prefix --
-// ::= ti <type> # typeid (type)
-// ::= te <expression> # typeid (expression)
-// ::= dc <type> <expression> # dynamic_cast<type> (expression)
-// ::= sc <type> <expression> # static_cast<type> (expression)
-// ::= cc <type> <expression> # const_cast<type> (expression)
-// ::= rc <type> <expression> # reinterpret_cast<type> (expression)
-// ::= st <type> # sizeof (a type)
-// ::= sz <expression> # sizeof (an expression)
-// ::= at <type> # alignof (a type)
-// ::= az <expression> # alignof (an expression)
-// ::= nx <expression> # noexcept (expression)
-// ::= <template-param>
-// ::= <function-param>
-// ::= dt <expression> <unresolved-name> # expr.name
-// ::= pt <expression> <unresolved-name> # expr->name
-// ::= ds <expression> <expression> # expr.*expr
-// ::= sZ <template-param> # size of a parameter pack
-// ::= sZ <function-param> # size of a function parameter pack
-// ::= sp <expression> # pack expansion
-// ::= tw <expression> # throw expression
-// ::= tr # throw with no operand (rethrow)
-// ::= <unresolved-name> # f(p), N::f(p), ::f(p),
-// # freestanding dependent name (e.g., T::x),
-// # objectless nonstatic member reference
-// ::= <expr-primary>
-
-template <class C>
-const char*
-parse_expression(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- const char* t = first;
- bool parsed_gs = false;
- if (last - first >= 4 && t[0] == 'g' && t[1] == 's')
- {
- t += 2;
- parsed_gs = true;
- }
- switch (*t)
- {
- case 'L':
- first = parse_expr_primary(first, last, db);
- break;
- case 'T':
- first = parse_template_param(first, last, db);
- break;
- case 'f':
- first = parse_function_param(first, last, db);
- break;
- case 'a':
- switch (t[1])
- {
- case 'a':
- t = parse_binary_expression(first+2, last, "&&", db);
- if (t != first+2)
- first = t;
- break;
- case 'd':
- t = parse_prefix_expression(first+2, last, "&", db);
- if (t != first+2)
- first = t;
- break;
- case 'n':
- t = parse_binary_expression(first+2, last, "&", db);
- if (t != first+2)
- first = t;
- break;
- case 'N':
- t = parse_binary_expression(first+2, last, "&=", db);
- if (t != first+2)
- first = t;
- break;
- case 'S':
- t = parse_binary_expression(first+2, last, "=", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- first = parse_alignof_type(first, last, db);
- break;
- case 'z':
- first = parse_alignof_expr(first, last, db);
- break;
- }
- break;
- case 'c':
- switch (t[1])
- {
- case 'c':
- first = parse_const_cast_expr(first, last, db);
- break;
- case 'l':
- first = parse_call_expr(first, last, db);
- break;
- case 'm':
- t = parse_binary_expression(first+2, last, ",", db);
- if (t != first+2)
- first = t;
- break;
- case 'o':
- t = parse_prefix_expression(first+2, last, "~", db);
- if (t != first+2)
- first = t;
- break;
- case 'v':
- first = parse_conversion_expr(first, last, db);
- break;
- }
- break;
- case 'd':
- switch (t[1])
- {
- case 'a':
- {
- const char* t1 = parse_expression(t+2, last, db);
- if (t1 != t+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
- "delete[] " + db.names.back().move_full();
- first = t1;
- }
- }
- break;
- case 'c':
- first = parse_dynamic_cast_expr(first, last, db);
- break;
- case 'e':
- t = parse_prefix_expression(first+2, last, "*", db);
- if (t != first+2)
- first = t;
- break;
- case 'l':
- {
- const char* t1 = parse_expression(t+2, last, db);
- if (t1 != t+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
- "delete " + db.names.back().move_full();
- first = t1;
- }
- }
- break;
- case 'n':
- return parse_unresolved_name(first, last, db);
- case 's':
- first = parse_dot_star_expr(first, last, db);
- break;
- case 't':
- first = parse_dot_expr(first, last, db);
- break;
- case 'v':
- t = parse_binary_expression(first+2, last, "/", db);
- if (t != first+2)
- first = t;
- break;
- case 'V':
- t = parse_binary_expression(first+2, last, "/=", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'e':
- switch (t[1])
- {
- case 'o':
- t = parse_binary_expression(first+2, last, "^", db);
- if (t != first+2)
- first = t;
- break;
- case 'O':
- t = parse_binary_expression(first+2, last, "^=", db);
- if (t != first+2)
- first = t;
- break;
- case 'q':
- t = parse_binary_expression(first+2, last, "==", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'g':
- switch (t[1])
- {
- case 'e':
- t = parse_binary_expression(first+2, last, ">=", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- t = parse_binary_expression(first+2, last, ">", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'i':
- if (t[1] == 'x')
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- const char* t2 = parse_expression(t1, last, db);
- if (t2 != t1)
- {
- if (db.names.size() < 2)
- return first;
- auto op2 = db.names.back().move_full();
- db.names.pop_back();
- auto op1 = db.names.back().move_full();
- db.names.back() = "(" + op1 + ")[" + op2 + "]";
- first = t2;
- }
- else
- db.names.pop_back();
- }
- }
- break;
- case 'l':
- switch (t[1])
- {
- case 'e':
- t = parse_binary_expression(first+2, last, "<=", db);
- if (t != first+2)
- first = t;
- break;
- case 's':
- t = parse_binary_expression(first+2, last, "<<", db);
- if (t != first+2)
- first = t;
- break;
- case 'S':
- t = parse_binary_expression(first+2, last, "<<=", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- t = parse_binary_expression(first+2, last, "<", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'm':
- switch (t[1])
- {
- case 'i':
- t = parse_binary_expression(first+2, last, "-", db);
- if (t != first+2)
- first = t;
- break;
- case 'I':
- t = parse_binary_expression(first+2, last, "-=", db);
- if (t != first+2)
- first = t;
- break;
- case 'l':
- t = parse_binary_expression(first+2, last, "*", db);
- if (t != first+2)
- first = t;
- break;
- case 'L':
- t = parse_binary_expression(first+2, last, "*=", db);
- if (t != first+2)
- first = t;
- break;
- case 'm':
- if (first+2 != last && first[2] == '_')
- {
- t = parse_prefix_expression(first+3, last, "--", db);
- if (t != first+3)
- first = t;
- }
- else
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "(" + db.names.back().move_full() + ")--";
- first = t1;
- }
- }
- break;
- }
- break;
- case 'n':
- switch (t[1])
- {
- case 'a':
- case 'w':
- first = parse_new_expr(first, last, db);
- break;
- case 'e':
- t = parse_binary_expression(first+2, last, "!=", db);
- if (t != first+2)
- first = t;
- break;
- case 'g':
- t = parse_prefix_expression(first+2, last, "-", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- t = parse_prefix_expression(first+2, last, "!", db);
- if (t != first+2)
- first = t;
- break;
- case 'x':
- t = parse_noexcept_expression(first+2, last, db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'o':
- switch (t[1])
- {
- case 'n':
- return parse_unresolved_name(first, last, db);
- case 'o':
- t = parse_binary_expression(first+2, last, "||", db);
- if (t != first+2)
- first = t;
- break;
- case 'r':
- t = parse_binary_expression(first+2, last, "|", db);
- if (t != first+2)
- first = t;
- break;
- case 'R':
- t = parse_binary_expression(first+2, last, "|=", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'p':
- switch (t[1])
- {
- case 'm':
- t = parse_binary_expression(first+2, last, "->*", db);
- if (t != first+2)
- first = t;
- break;
- case 'l':
- t = parse_binary_expression(first+2, last, "+", db);
- if (t != first+2)
- first = t;
- break;
- case 'L':
- t = parse_binary_expression(first+2, last, "+=", db);
- if (t != first+2)
- first = t;
- break;
- case 'p':
- if (first+2 != last && first[2] == '_')
- {
- t = parse_prefix_expression(first+3, last, "++", db);
- if (t != first+3)
- first = t;
- }
- else
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "(" + db.names.back().move_full() + ")++";
- first = t1;
- }
- }
- break;
- case 's':
- t = parse_prefix_expression(first+2, last, "+", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- first = parse_arrow_expr(first, last, db);
- break;
- }
- break;
- case 'q':
- if (t[1] == 'u')
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- const char* t2 = parse_expression(t1, last, db);
- if (t2 != t1)
- {
- const char* t3 = parse_expression(t2, last, db);
- if (t3 != t2)
- {
- if (db.names.size() < 3)
- return first;
- auto op3 = db.names.back().move_full();
- db.names.pop_back();
- auto op2 = db.names.back().move_full();
- db.names.pop_back();
- auto op1 = db.names.back().move_full();
- db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")";
- first = t3;
- }
- else
- {
- db.names.pop_back();
- db.names.pop_back();
- }
- }
- else
- db.names.pop_back();
- }
- }
- break;
- case 'r':
- switch (t[1])
- {
- case 'c':
- first = parse_reinterpret_cast_expr(first, last, db);
- break;
- case 'm':
- t = parse_binary_expression(first+2, last, "%", db);
- if (t != first+2)
- first = t;
- break;
- case 'M':
- t = parse_binary_expression(first+2, last, "%=", db);
- if (t != first+2)
- first = t;
- break;
- case 's':
- t = parse_binary_expression(first+2, last, ">>", db);
- if (t != first+2)
- first = t;
- break;
- case 'S':
- t = parse_binary_expression(first+2, last, ">>=", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 's':
- switch (t[1])
- {
- case 'c':
- first = parse_static_cast_expr(first, last, db);
- break;
- case 'p':
- first = parse_pack_expansion(first, last, db);
- break;
- case 'r':
- return parse_unresolved_name(first, last, db);
- case 't':
- first = parse_sizeof_type_expr(first, last, db);
- break;
- case 'z':
- first = parse_sizeof_expr_expr(first, last, db);
- break;
- case 'Z':
- if (last - t >= 3)
- {
- switch (t[2])
- {
- case 'T':
- first = parse_sizeof_param_pack_expr(first, last, db);
- break;
- case 'f':
- first = parse_sizeof_function_param_pack_expr(first, last, db);
- break;
- }
- }
- break;
- }
- break;
- case 't':
- switch (t[1])
- {
- case 'e':
- case 'i':
- first = parse_typeid_expr(first, last, db);
- break;
- case 'r':
- db.names.push_back("throw");
- first += 2;
- break;
- case 'w':
- first = parse_throw_expr(first, last, db);
- break;
- }
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return parse_unresolved_name(first, last, db);
- }
- }
- return first;
-}
-
-// <template-arg> ::= <type> # type or template
-// ::= X <expression> E # expression
-// ::= <expr-primary> # simple expressions
-// ::= J <template-arg>* E # argument pack
-// ::= LZ <encoding> E # extension
-
-template <class C>
-const char*
-parse_template_arg(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- const char* t;
- switch (*first)
- {
- case 'X':
- t = parse_expression(first+1, last, db);
- if (t != first+1)
- {
- if (t != last && *t == 'E')
- first = t+1;
- }
- break;
- case 'J':
- t = first+1;
- if (t == last)
- return first;
- while (*t != 'E')
- {
- const char* t1 = parse_template_arg(t, last, db);
- if (t1 == t)
- return first;
- t = t1;
- }
- first = t+1;
- break;
- case 'L':
- // <expr-primary> or LZ <encoding> E
- if (first+1 != last && first[1] == 'Z')
- {
- t = parse_encoding(first+2, last, db);
- if (t != first+2 && t != last && *t == 'E')
- first = t+1;
- }
- else
- first = parse_expr_primary(first, last, db);
- break;
- default:
- // <type>
- first = parse_type(first, last, db);
- break;
- }
- }
- return first;
-}
-
-// <template-args> ::= I <template-arg>* E
-// extension, the abi says <template-arg>+
-
-template <class C>
-const char*
-parse_template_args(const char* first, const char* last, C& db)
-{
- if (last - first >= 2 && *first == 'I')
- {
- if (db.tag_templates)
- db.template_param.back().clear();
- const char* t = first+1;
- typename C::String args("<");
- while (*t != 'E')
- {
- if (db.tag_templates)
- db.template_param.emplace_back(db.names.get_allocator());
- size_t k0 = db.names.size();
- const char* t1 = parse_template_arg(t, last, db);
- size_t k1 = db.names.size();
- if (db.tag_templates)
- db.template_param.pop_back();
- if (t1 == t || t1 == last)
- return first;
- if (db.tag_templates)
- {
- db.template_param.back().emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- db.template_param.back().back().push_back(db.names[k]);
- }
- for (size_t k = k0; k < k1; ++k)
- {
- if (args.size() > 1)
- args += ", ";
- args += db.names[k].move_full();
- }
- for (; k1 != k0; --k1)
- db.names.pop_back();
- t = t1;
- }
- first = t + 1;
- if (args.back() != '>')
- args += ">";
- else
- args += " >";
- db.names.push_back(std::move(args));
-
- }
- return first;
-}
-
-// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
-// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
-//
-// <prefix> ::= <prefix> <unqualified-name>
-// ::= <template-prefix> <template-args>
-// ::= <template-param>
-// ::= <decltype>
-// ::= # empty
-// ::= <substitution>
-// ::= <prefix> <data-member-prefix>
-// extension ::= L
-//
-// <template-prefix> ::= <prefix> <template unqualified-name>
-// ::= <template-param>
-// ::= <substitution>
-
-template <class C>
-const char*
-parse_nested_name(const char* first, const char* last, C& db)
-{
- if (first != last && *first == 'N')
- {
- unsigned cv;
- const char* t0 = parse_cv_qualifiers(first+1, last, cv);
- if (t0 == last)
- return first;
- unsigned ref = 0;
- if (*t0 == 'R')
- {
- ref = 1;
- ++t0;
- }
- else if (*t0 == 'O')
- {
- ref = 2;
- ++t0;
- }
- db.names.emplace_back();
- if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
- {
- t0 += 2;
- db.names.back().first = "std";
- }
- if (t0 == last)
- {
- db.names.pop_back();
- return first;
- }
- bool pop_subs = false;
- while (*t0 != 'E')
- {
- const char* t1;
- switch (*t0)
- {
- case 'S':
- if (t0 + 1 != last && t0[1] == 't')
- goto do_parse_unqualified_name;
- t1 = parse_substitution(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- auto name = db.names.back().move_full();
- db.names.pop_back();
- if (!db.names.back().first.empty())
- {
- db.names.back().first += "::" + name;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- else
- db.names.back().first = name;
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'T':
- t1 = parse_template_param(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- auto name = db.names.back().move_full();
- db.names.pop_back();
- if (!db.names.back().first.empty())
- db.names.back().first += "::" + name;
- else
- db.names.back().first = name;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'D':
- if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
- goto do_parse_unqualified_name;
- t1 = parse_decltype(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- auto name = db.names.back().move_full();
- db.names.pop_back();
- if (!db.names.back().first.empty())
- db.names.back().first += "::" + name;
- else
- db.names.back().first = name;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'I':
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- auto name = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += name;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- t0 = t1;
- }
- else
- return first;
- break;
- case 'L':
- if (++t0 == last)
- return first;
- break;
- default:
- do_parse_unqualified_name:
- t1 = parse_unqualified_name(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- auto name = db.names.back().move_full();
- db.names.pop_back();
- if (!db.names.back().first.empty())
- db.names.back().first += "::" + name;
- else
- db.names.back().first = name;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- }
- }
- first = t0 + 1;
- db.ref = ref;
- db.cv = cv;
- if (pop_subs && !db.subs.empty())
- db.subs.pop_back();
- }
- return first;
-}
-
-// <discriminator> := _ <non-negative number> # when number < 10
-// := __ <non-negative number> _ # when number >= 10
-// extension := decimal-digit+
-
-const char*
-parse_discriminator(const char* first, const char* last)
-{
- // parse but ignore discriminator
- if (first != last)
- {
- if (*first == '_')
- {
- const char* t1 = first+1;
- if (t1 != last)
- {
- if (std::isdigit(*t1))
- first = t1+1;
- else if (*t1 == '_')
- {
- for (++t1; t1 != last && std::isdigit(*t1); ++t1)
- ;
- if (t1 != last && *t1 == '_')
- first = t1 + 1;
- }
- }
- }
- else if (std::isdigit(*first))
- {
- const char* t1 = first+1;
- for (; t1 != last && std::isdigit(*t1); ++t1)
- ;
- first = t1;
- }
- }
- return first;
-}
-
-// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
-// := Z <function encoding> E s [<discriminator>]
-// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
-
-template <class C>
-const char*
-parse_local_name(const char* first, const char* last, C& db)
-{
- if (first != last && *first == 'Z')
- {
- const char* t = parse_encoding(first+1, last, db);
- if (t != first+1 && t != last && *t == 'E' && ++t != last)
- {
- switch (*t)
- {
- case 's':
- first = parse_discriminator(t+1, last);
- if (db.names.empty())
- return first;
- db.names.back().first.append("::string literal");
- break;
- case 'd':
- if (++t != last)
- {
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
- {
- t = t1 + 1;
- t1 = parse_name(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto name = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first.append("::");
- db.names.back().first.append(name);
- first = t1;
- }
- else
- db.names.pop_back();
- }
- }
- break;
- default:
- {
- const char* t1 = parse_name(t, last, db);
- if (t1 != t)
- {
- // parse but ignore discriminator
- first = parse_discriminator(t1, last);
- if (db.names.size() < 2)
- return first;
- auto name = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first.append("::");
- db.names.back().first.append(name);
- }
- else
- db.names.pop_back();
- }
- break;
- }
- }
- }
- return first;
-}
-
-// <name> ::= <nested-name> // N
-// ::= <local-name> # See Scope Encoding below // Z
-// ::= <unscoped-template-name> <template-args>
-// ::= <unscoped-name>
-
-// <unscoped-template-name> ::= <unscoped-name>
-// ::= <substitution>
-
-template <class C>
-const char*
-parse_name(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- const char* t0 = first;
- // extension: ignore L here
- if (*t0 == 'L')
- ++t0;
- switch (*t0)
- {
- case 'N':
- {
- const char* t1 = parse_nested_name(t0, last, db);
- if (t1 != t0)
- first = t1;
- break;
- }
- case 'Z':
- {
- const char* t1 = parse_local_name(t0, last, db);
- if (t1 != t0)
- first = t1;
- break;
- }
- default:
- {
- const char* t1 = parse_unscoped_name(t0, last, db);
- if (t1 != t0)
- {
- if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args>
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- t0 = t1;
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0)
- {
- if (db.names.size() < 2)
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += tmp;
- first = t1;
- }
- }
- else // <unscoped-name>
- first = t1;
- }
- else
- { // try <substitution> <template-args>
- t1 = parse_substitution(t0, last, db);
- if (t1 != t0 && t1 != last && *t1 == 'I')
- {
- t0 = t1;
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0)
- {
- if (db.names.size() < 2)
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += tmp;
- first = t1;
- }
- }
- }
- break;
- }
- }
- }
- return first;
-}
-
-// <call-offset> ::= h <nv-offset> _
-// ::= v <v-offset> _
-//
-// <nv-offset> ::= <offset number>
-// # non-virtual base override
-//
-// <v-offset> ::= <offset number> _ <virtual offset number>
-// # virtual base override, with vcall offset
-
-const char*
-parse_call_offset(const char* first, const char* last)
-{
- if (first != last)
- {
- switch (*first)
- {
- case 'h':
- {
- const char* t = parse_number(first + 1, last);
- if (t != first + 1 && t != last && *t == '_')
- first = t + 1;
- }
- break;
- case 'v':
- {
- const char* t = parse_number(first + 1, last);
- if (t != first + 1 && t != last && *t == '_')
- {
- const char* t2 = parse_number(++t, last);
- if (t2 != t && t2 != last && *t2 == '_')
- first = t2 + 1;
- }
- }
- break;
- }
- }
- return first;
-}
-
-// <special-name> ::= TV <type> # virtual table
-// ::= TT <type> # VTT structure (construction vtable index)
-// ::= TI <type> # typeinfo structure
-// ::= TS <type> # typeinfo name (null-terminated byte string)
-// ::= Tc <call-offset> <call-offset> <base encoding>
-// # base is the nominal target function of thunk
-// # first call-offset is 'this' adjustment
-// # second call-offset is result adjustment
-// ::= T <call-offset> <base encoding>
-// # base is the nominal target function of thunk
-// ::= GV <object name> # Guard variable for one-time initialization
-// # No <type>
-// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
-// extension ::= GR <object name> # reference temporary for object
-
-template <class C>
-const char*
-parse_special_name(const char* first, const char* last, C& db)
-{
- if (last - first > 2)
- {
- const char* t;
- switch (*first)
- {
- case 'T':
- switch (first[1])
- {
- case 'V':
- // TV <type> # virtual table
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "vtable for ");
- first = t;
- }
- break;
- case 'T':
- // TT <type> # VTT structure (construction vtable index)
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "VTT for ");
- first = t;
- }
- break;
- case 'I':
- // TI <type> # typeinfo structure
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "typeinfo for ");
- first = t;
- }
- break;
- case 'S':
- // TS <type> # typeinfo name (null-terminated byte string)
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "typeinfo name for ");
- first = t;
- }
- break;
- case 'c':
- // Tc <call-offset> <call-offset> <base encoding>
- {
- const char* t0 = parse_call_offset(first+2, last);
- if (t0 == first+2)
- break;
- const char* t1 = parse_call_offset(t0, last);
- if (t1 == t0)
- break;
- t = parse_encoding(t1, last, db);
- if (t != t1)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "covariant return thunk to ");
- first = t;
- }
- }
- break;
- case 'C':
- // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t0 = parse_number(t, last);
- if (t0 != t && t0 != last && *t0 == '_')
- {
- const char* t1 = parse_type(++t0, last, db);
- if (t1 != t0)
- {
- if (db.names.size() < 2)
- return first;
- auto left = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first = "construction vtable for " +
- std::move(left) + "-in-" +
- db.names.back().move_full();
- first = t1;
- }
- }
- }
- break;
- default:
- // T <call-offset> <base encoding>
- {
- const char* t0 = parse_call_offset(first+1, last);
- if (t0 == first+1)
- break;
- t = parse_encoding(t0, last, db);
- if (t != t0)
- {
- if (db.names.empty())
- return first;
- if (first[1] == 'v')
- {
- db.names.back().first.insert(0, "virtual thunk to ");
- first = t;
- }
- else
- {
- db.names.back().first.insert(0, "non-virtual thunk to ");
- first = t;
- }
- }
- }
- break;
- }
- break;
- case 'G':
- switch (first[1])
- {
- case 'V':
- // GV <object name> # Guard variable for one-time initialization
- t = parse_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "guard variable for ");
- first = t;
- }
- break;
- case 'R':
- // extension ::= GR <object name> # reference temporary for object
- t = parse_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "reference temporary for ");
- first = t;
- }
- break;
- }
- break;
- }
- }
- return first;
-}
-
-template <class T>
-class save_value
-{
- T& restore_;
- T original_value_;
-public:
- save_value(T& restore)
- : restore_(restore),
- original_value_(restore)
- {}
-
- ~save_value()
- {
- restore_ = std::move(original_value_);
- }
-
- save_value(const save_value&) = delete;
- save_value& operator=(const save_value&) = delete;
-};
-
-// <encoding> ::= <function name> <bare-function-type>
-// ::= <data name>
-// ::= <special-name>
-
-template <class C>
-const char*
-parse_encoding(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
- ++db.encoding_depth;
- save_value<decltype(db.tag_templates)> sb(db.tag_templates);
- if (db.encoding_depth > 1)
- db.tag_templates = true;
- switch (*first)
- {
- case 'G':
- case 'T':
- first = parse_special_name(first, last, db);
- break;
- default:
- {
- const char* t = parse_name(first, last, db);
- unsigned cv = db.cv;
- unsigned ref = db.ref;
- if (t != first)
- {
- if (t != last && *t != 'E' && *t != '.')
- {
- save_value<bool> sb2(db.tag_templates);
- db.tag_templates = false;
- const char* t2;
- typename C::String ret2;
- if (db.names.empty())
- return first;
- const typename C::String& nm = db.names.back().first;
- if (nm.empty())
- return first;
- if (!db.parsed_ctor_dtor_cv && nm.back() == '>' && nm[nm.size()-2] != '-'
- && nm[nm.size()-2] != '>')
- {
- t2 = parse_type(t, last, db);
- if (t2 == t)
- return first;
- if (db.names.size() < 2)
- return first;
- auto ret1 = std::move(db.names.back().first);
- ret2 = std::move(db.names.back().second);
- if (ret2.empty())
- ret1 += ' ';
- db.names.pop_back();
- db.names.back().first.insert(0, ret1);
- t = t2;
- }
- db.names.back().first += '(';
- if (t != last && *t == 'v')
- {
- ++t;
- }
- else
- {
- bool first_arg = true;
- while (true)
- {
- size_t k0 = db.names.size();
- t2 = parse_type(t, last, db);
- size_t k1 = db.names.size();
- if (t2 == t)
- break;
- if (k1 > k0)
- {
- typename C::String tmp;
- for (size_t k = k0; k < k1; ++k)
- {
- if (!tmp.empty())
- tmp += ", ";
- tmp += db.names[k].move_full();
- }
- for (size_t k = k0; k < k1; ++k)
- db.names.pop_back();
- if (!tmp.empty())
- {
- if (db.names.empty())
- return first;
- if (!first_arg)
- db.names.back().first += ", ";
- else
- first_arg = false;
- db.names.back().first += tmp;
- }
- }
- t = t2;
- }
- }
- if (db.names.empty())
- return first;
- db.names.back().first += ')';
- if (cv & 1)
- db.names.back().first.append(" const");
- if (cv & 2)
- db.names.back().first.append(" volatile");
- if (cv & 4)
- db.names.back().first.append(" restrict");
- if (ref == 1)
- db.names.back().first.append(" &");
- else if (ref == 2)
- db.names.back().first.append(" &&");
- db.names.back().first += ret2;
- first = t;
- }
- else
- first = t;
- }
- break;
- }
- }
- }
- return first;
-}
-
-// _block_invoke
-// _block_invoke<decimal-digit>+
-// _block_invoke_<decimal-digit>+
-
-template <class C>
-const char*
-parse_block_invoke(const char* first, const char* last, C& db)
-{
- if (last - first >= 13)
- {
- const char test[] = "_block_invoke";
- const char* t = first;
- for (int i = 0; i < 13; ++i, ++t)
- {
- if (*t != test[i])
- return first;
- }
- if (t != last)
- {
- if (*t == '_')
- {
- // must have at least 1 decimal digit
- if (++t == last || !std::isdigit(*t))
- return first;
- ++t;
- }
- // parse zero or more digits
- while (t != last && isdigit(*t))
- ++t;
- }
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "invocation function for block in ");
- first = t;
- }
- return first;
-}
-
-// extension
-// <dot-suffix> := .<anything and everything>
-
-template <class C>
-const char*
-parse_dot_suffix(const char* first, const char* last, C& db)
-{
- if (first != last && *first == '.')
- {
- if (db.names.empty())
- return first;
- db.names.back().first += " (" + typename C::String(first, last) + ")";
- first = last;
- }
- return first;
-}
-
-// <block-involcaton-function> ___Z<encoding>_block_invoke
-// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
-// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
-// <mangled-name> ::= _Z<encoding>
-// ::= <type>
-
-template <class C>
-void
-demangle(const char* first, const char* last, C& db, int& status)
-{
- if (first >= last)
- {
- status = invalid_mangled_name;
- return;
- }
- if (*first == '_')
- {
- if (last - first >= 4)
- {
- if (first[1] == 'Z')
- {
- const char* t = parse_encoding(first+2, last, db);
- if (t != first+2 && t != last && *t == '.')
- t = parse_dot_suffix(t, last, db);
- if (t != last)
- status = invalid_mangled_name;
- }
- else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z')
- {
- const char* t = parse_encoding(first+4, last, db);
- if (t != first+4 && t != last)
- {
- const char* t1 = parse_block_invoke(t, last, db);
- if (t1 != last)
- status = invalid_mangled_name;
- }
- else
- status = invalid_mangled_name;
- }
- else
- status = invalid_mangled_name;
- }
- else
- status = invalid_mangled_name;
- }
- else
- {
- const char* t = parse_type(first, last, db);
- if (t != last)
- status = invalid_mangled_name;
- }
- if (status == success && db.names.empty())
- status = invalid_mangled_name;
-}
-
-template <std::size_t N>
-class arena
-{
- static const std::size_t alignment = 16;
- alignas(alignment) char buf_[N];
- char* ptr_;
-
- std::size_t
- align_up(std::size_t n) noexcept
- {return n + (alignment-1) & ~(alignment-1);}
-
- bool
- pointer_in_buffer(char* p) noexcept
- {return buf_ <= p && p <= buf_ + N;}
-
-public:
- arena() noexcept : ptr_(buf_) {}
- ~arena() {ptr_ = nullptr;}
- arena(const arena&) = delete;
- arena& operator=(const arena&) = delete;
-
- char* allocate(std::size_t n);
- void deallocate(char* p, std::size_t n) noexcept;
-
- static constexpr std::size_t size() {return N;}
- std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);}
- void reset() {ptr_ = buf_;}
-};
-
-template <std::size_t N>
-char*
-arena<N>::allocate(std::size_t n)
-{
- n = align_up(n);
- if (static_cast<std::size_t>(buf_ + N - ptr_) >= n)
- {
- char* r = ptr_;
- ptr_ += n;
- return r;
- }
- return static_cast<char*>(std::malloc(n));
-}
-
-template <std::size_t N>
-void
-arena<N>::deallocate(char* p, std::size_t n) noexcept
-{
- if (pointer_in_buffer(p))
- {
- n = align_up(n);
- if (p + n == ptr_)
- ptr_ = p;
- }
- else
- std::free(p);
-}
-
-template <class T, std::size_t N>
-class short_alloc
-{
- arena<N>& a_;
-public:
- typedef T value_type;
-
-public:
- template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;};
-
- short_alloc(arena<N>& a) noexcept : a_(a) {}
- template <class U>
- short_alloc(const short_alloc<U, N>& a) noexcept
- : a_(a.a_) {}
- short_alloc(const short_alloc&) = default;
- short_alloc& operator=(const short_alloc&) = delete;
-
- T* allocate(std::size_t n)
- {
- return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));
- }
- void deallocate(T* p, std::size_t n) noexcept
- {
- a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
- }
-
- template <class T1, std::size_t N1, class U, std::size_t M>
- friend
- bool
- operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept;
-
- template <class U, std::size_t M> friend class short_alloc;
-};
-
-template <class T, std::size_t N, class U, std::size_t M>
-inline
-bool
-operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
-{
- return N == M && &x.a_ == &y.a_;
-}
-
-template <class T, std::size_t N, class U, std::size_t M>
-inline
-bool
-operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
-{
- return !(x == y);
-}
-
-template <class T>
-class malloc_alloc
-{
-public:
- typedef T value_type;
-
- malloc_alloc() = default;
- template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {}
-
- T* allocate(std::size_t n)
- {
- return static_cast<T*>(std::malloc(n*sizeof(T)));
- }
- void deallocate(T* p, std::size_t) noexcept
- {
- std::free(p);
- }
-};
-
-template <class T, class U>
-inline
-bool
-operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept
-{
- return true;
-}
-
-template <class T, class U>
-inline
-bool
-operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept
-{
- return !(x == y);
-}
-
-const size_t bs = 4 * 1024;
-template <class T> using Alloc = short_alloc<T, bs>;
-template <class T> using Vector = std::vector<T, Alloc<T>>;
-using String = std::basic_string<char, std::char_traits<char>, malloc_alloc<char>>;
-
-struct string_pair
-{
- String first;
- String second;
-
- string_pair() = default;
- string_pair(String f) : first(std::move(f)) {}
- string_pair(String f, String s)
- : first(std::move(f)), second(std::move(s)) {}
- template <size_t N>
- string_pair(const char (&s)[N]) : first(s, N-1) {}
-
- size_t size() const {return first.size() + second.size();}
- String full() const {return first + second;}
- String move_full() {return std::move(first) + std::move(second);}
-};
-
-struct Db
-{
- typedef String String;
- typedef Vector<string_pair> sub_type;
- typedef Vector<sub_type> template_param_type;
- Vector<string_pair> names;
- Vector<sub_type> subs;
- Vector<template_param_type> template_param;
- unsigned cv;
- unsigned ref;
- unsigned encoding_depth;
- bool parsed_ctor_dtor_cv;
- bool tag_templates;
- bool fix_forward_references;
- bool try_to_parse_template_args;
-
- template <size_t N>
- Db(arena<N>& ar) :
- names(ar),
- subs(0, names, ar),
- template_param(0, subs, ar)
- {}
-};
-
-char*
-__cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
-{
- if (mangled_name == nullptr || (buf != nullptr && n == nullptr))
- {
- if (status)
- *status = invalid_args;
- return nullptr;
- }
- size_t internal_size = buf != nullptr ? *n : 0;
- arena<bs> a;
- Db db(a);
- db.cv = 0;
- db.ref = 0;
- db.encoding_depth = 0;
- db.parsed_ctor_dtor_cv = false;
- db.tag_templates = true;
- db.template_param.emplace_back(a);
- db.fix_forward_references = false;
- db.try_to_parse_template_args = true;
- int internal_status = success;
- size_t len = std::strlen(mangled_name);
- demangle(mangled_name, mangled_name + len, db,
- internal_status);
- if (internal_status == success && db.fix_forward_references &&
- !db.template_param.empty() && !db.template_param.front().empty())
- {
- db.fix_forward_references = false;
- db.tag_templates = false;
- db.names.clear();
- db.subs.clear();
- demangle(mangled_name, mangled_name + len, db, internal_status);
- if (db.fix_forward_references)
- internal_status = invalid_mangled_name;
- }
- if (internal_status == success)
- {
- size_t sz = db.names.back().size() + 1;
- if (sz > internal_size)
- {
- char* newbuf = static_cast<char*>(std::realloc(buf, sz));
- if (newbuf == nullptr)
- {
- internal_status = memory_alloc_failure;
- buf = nullptr;
- }
- else
- {
- buf = newbuf;
- if (n != nullptr)
- *n = sz;
- }
- }
- if (buf != nullptr)
- {
- db.names.back().first += db.names.back().second;
- std::memcpy(buf, db.names.back().first.data(), sz-1);
- buf[sz-1] = char(0);
- }
- }
- else
- buf = nullptr;
- if (status)
- *status = internal_status;
- return buf;
-}
-
-}
#endif
@@ -4995,16 +46,23 @@ __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
using namespace lldb_private;
-static inline bool
-cstring_is_mangled (const char *s)
+static inline Mangled::ManglingScheme
+cstring_mangling_scheme(const char *s)
{
if (s)
-#if defined(_MSC_VER)
- return (s[0] == '?');
-#else
- return (s[0] == '_' && s[1] == 'Z');
-#endif
- return false;
+ {
+ if (s[0] == '?')
+ return Mangled::eManglingSchemeMSVC;
+ if (s[0] == '_' && s[1] == 'Z')
+ return Mangled::eManglingSchemeItanium;
+ }
+ return Mangled::eManglingSchemeNone;
+}
+
+static inline bool
+cstring_is_mangled(const char *s)
+{
+ return cstring_mangling_scheme(s) != Mangled::eManglingSchemeNone;
}
static const ConstString &
@@ -5134,7 +192,7 @@ Mangled::Clear ()
//----------------------------------------------------------------------
-// Compare the the string values.
+// Compare the string values.
//----------------------------------------------------------------------
int
Mangled::Compare (const Mangled& a, const Mangled& b)
@@ -5215,45 +273,58 @@ Mangled::GetDemangledName () const
m_mangled.GetCString());
// Don't bother running anything that isn't mangled
- const char *mangled_cstr = m_mangled.GetCString();
- if (cstring_is_mangled(mangled_cstr))
+ const char *mangled_name = m_mangled.GetCString();
+ ManglingScheme mangling_scheme{cstring_mangling_scheme(mangled_name)};
+ if (mangling_scheme != eManglingSchemeNone &&
+ !m_mangled.GetMangledCounterpart(m_demangled))
{
- if (!m_mangled.GetMangledCounterpart(m_demangled))
+ // We didn't already mangle this name, demangle it and if all goes well
+ // add it to our map.
+ char *demangled_name = nullptr;
+ switch (mangling_scheme)
{
- // We didn't already mangle this name, demangle it and if all goes well
- // add it to our map.
-#ifdef LLDB_USE_BUILTIN_DEMANGLER
- // 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)
- char *demangled_name = (char *)::malloc(1024);
- ::ZeroMemory(demangled_name, 1024);
- DWORD result = ::UnDecorateSymbolName(mangled_cstr, demangled_name, 1023,
- UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected keywords
- UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc keywords
- UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications
- UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers
- UNDNAME_NO_MS_KEYWORDS // Strip all MS extension keywords
- );
- if (result == 0)
+ case eManglingSchemeMSVC:
{
- free (demangled_name);
- demangled_name = nullptr;
+#if defined(_MSC_VER)
+ const size_t demangled_length = 2048;
+ demangled_name = static_cast<char *>(::malloc(demangled_length));
+ ::ZeroMemory(demangled_name, demangled_length);
+ DWORD result = ::UnDecorateSymbolName(mangled_name, demangled_name, demangled_length,
+ UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected keywords
+ UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc keywords
+ UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications
+ UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers
+ UNDNAME_NO_MS_KEYWORDS // Strip all MS extension keywords
+ );
+ if (result == 0)
+ {
+ free(demangled_name);
+ demangled_name = nullptr;
+ }
+#endif
+ break;
}
+ case eManglingSchemeItanium:
+ {
+#ifdef LLDB_USE_BUILTIN_DEMANGLER
+ // Try to use the fast-path demangler first for the
+ // performance win, falling back to the full demangler only
+ // when necessary
+ demangled_name = FastDemangle(mangled_name, m_mangled.GetLength());
+ if (!demangled_name)
+ demangled_name = __cxa_demangle(mangled_name, NULL, NULL, NULL);
#else
- char *demangled_name = abi::__cxa_demangle (mangled_cstr, NULL, NULL, NULL);
+ demangled_name = abi::__cxa_demangle(mangled_name, NULL, NULL, NULL);
#endif
-
- if (demangled_name)
- {
- m_demangled.SetCStringWithMangledCounterpart(demangled_name, m_mangled);
- free (demangled_name);
+ break;
}
+ case eManglingSchemeNone:
+ break;
+ }
+ if (demangled_name)
+ {
+ m_demangled.SetCStringWithMangledCounterpart(demangled_name, m_mangled);
+ free(demangled_name);
}
}
if (!m_demangled)
@@ -5353,7 +424,7 @@ Mangled::MemorySize () const
}
lldb::LanguageType
-Mangled::GetLanguage ()
+Mangled::GuessLanguage () const
{
ConstString mangled = GetMangledName();
if (mangled)
diff --git a/source/Core/Module.cpp b/source/Core/Module.cpp
index 891bd87a20d4..eb0359d02d5b 100644
--- a/source/Core/Module.cpp
+++ b/source/Core/Module.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/AddressResolverFileLine.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Module.h"
@@ -25,7 +23,7 @@
#include "lldb/Host/Symbols.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
-#include "lldb/lldb-private-log.h"
+#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
@@ -39,6 +37,9 @@
#include "Plugins/ObjectFile/JIT/ObjectFileJIT.h"
+#include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Support/Signals.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -145,7 +146,7 @@ Module::Module (const ModuleSpec &module_spec) :
m_object_mod_time (),
m_objfile_sp (),
m_symfile_ap (),
- m_ast (),
+ m_ast (new ClangASTContext),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
@@ -249,7 +250,7 @@ Module::Module(const FileSpec& file_spec,
m_object_mod_time (),
m_objfile_sp (),
m_symfile_ap (),
- m_ast (),
+ m_ast (new ClangASTContext),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
@@ -295,7 +296,7 @@ Module::Module () :
m_object_mod_time (),
m_objfile_sp (),
m_symfile_ap (),
- m_ast (),
+ m_ast (new ClangASTContext),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
@@ -440,10 +441,10 @@ Module::GetClangASTContext ()
object_arch.GetTriple().setOS(llvm::Triple::MacOSX);
}
}
- m_ast.SetArchitecture (object_arch);
+ m_ast->SetArchitecture (object_arch);
}
}
- return m_ast;
+ return *m_ast;
}
void
@@ -901,10 +902,9 @@ Module::FindFunctions (const RegularExpression& regex,
{
sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
SymbolType sym_type = sc.symbol->GetType();
- if (sc.symbol && (sym_type == eSymbolTypeCode ||
- sym_type == eSymbolTypeResolver))
+ if (sc.symbol && sc.symbol->ValueIsAddress() && (sym_type == eSymbolTypeCode || sym_type == eSymbolTypeResolver))
{
- FileAddrToIndexMap::const_iterator pos = file_addr_to_index.find(sc.symbol->GetAddress().GetFileAddress());
+ FileAddrToIndexMap::const_iterator pos = file_addr_to_index.find(sc.symbol->GetAddressRef().GetFileAddress());
if (pos == end)
sc_list.Append(sc);
else
@@ -1233,7 +1233,12 @@ Module::LogMessageVerboseBacktrace (Log *log, const char *format, ...)
log_message.PrintfVarArg (format, args);
va_end (args);
if (log->GetVerbose())
- Host::Backtrace (log_message, 1024);
+ {
+ std::string back_trace;
+ llvm::raw_string_ostream stream(back_trace);
+ llvm::sys::PrintStackTrace(stream);
+ log_message.PutCString(back_trace.c_str());
+ }
log->PutCString(log_message.GetString().c_str());
}
}
@@ -1461,9 +1466,11 @@ Module::FindSymbolsMatchingRegExAndType (const RegularExpression &regex, SymbolT
void
Module::SetSymbolFileFileSpec (const FileSpec &file)
{
- // Remove any sections in the unified section list that come from the current symbol vendor.
+ if (!file.Exists())
+ return;
if (m_symfile_ap)
{
+ // Remove any sections in the unified section list that come from the current symbol vendor.
SectionList *section_list = GetSectionList();
SymbolFile *symbol_file = m_symfile_ap->GetSymbolFile();
if (section_list && symbol_file)
@@ -1471,21 +1478,49 @@ Module::SetSymbolFileFileSpec (const FileSpec &file)
ObjectFile *obj_file = symbol_file->GetObjectFile();
// Make sure we have an object file and that the symbol vendor's objfile isn't
// the same as the module's objfile before we remove any sections for it...
- if (obj_file && obj_file != m_objfile_sp.get())
+ if (obj_file)
{
- size_t num_sections = section_list->GetNumSections (0);
- for (size_t idx = num_sections; idx > 0; --idx)
+ // Check to make sure we aren't trying to specify the file we already have
+ if (obj_file->GetFileSpec() == file)
{
- lldb::SectionSP section_sp (section_list->GetSectionAtIndex (idx - 1));
- if (section_sp->GetObjectFile() == obj_file)
+ // We are being told to add the exact same file that we already have
+ // we don't have to do anything.
+ return;
+ }
+
+ // The symbol file might be a directory bundle ("/tmp/a.out.dSYM") instead
+ // of a full path to the symbol file within the bundle
+ // ("/tmp/a.out.dSYM/Contents/Resources/DWARF/a.out"). So we need to check this
+
+ if (file.IsDirectory())
+ {
+ std::string new_path(file.GetPath());
+ std::string old_path(obj_file->GetFileSpec().GetPath());
+ if (old_path.find(new_path) == 0)
+ {
+ // We specified the same bundle as the symbol file that we already have
+ return;
+ }
+ }
+
+ if (obj_file != m_objfile_sp.get())
+ {
+ size_t num_sections = section_list->GetNumSections (0);
+ for (size_t idx = num_sections; idx > 0; --idx)
{
- section_list->DeleteSection (idx - 1);
+ lldb::SectionSP section_sp (section_list->GetSectionAtIndex (idx - 1));
+ if (section_sp->GetObjectFile() == obj_file)
+ {
+ section_list->DeleteSection (idx - 1);
+ }
}
}
}
}
+ // Keep all old symbol files around in case there are any lingering type references in
+ // any SBValue objects that might have been handed out.
+ m_old_symfiles.push_back(std::move(m_symfile_ap));
}
-
m_symfile_spec = file;
m_symfile_ap.reset();
m_did_load_symbol_vendor = false;
@@ -1608,7 +1643,7 @@ Module::SetArchitecture (const ArchSpec &new_arch)
m_arch = new_arch;
return true;
}
- return m_arch.IsExactMatch(new_arch);
+ return m_arch.IsCompatibleMatch(new_arch);
}
bool
diff --git a/source/Core/ModuleList.cpp b/source/Core/ModuleList.cpp
index 879eb9bd1822..669b3d9274cc 100644
--- a/source/Core/ModuleList.cpp
+++ b/source/Core/ModuleList.cpp
@@ -978,14 +978,46 @@ ModuleList::GetSharedModule
if (module_sp)
return error;
+
+ module_sp.reset (new Module (module_spec));
+ // Make sure there are a module and an object file since we can specify
+ // a valid file path with an architecture that might not be in that file.
+ // By getting the object file we can guarantee that the architecture matches
+ if (module_sp->GetObjectFile())
+ {
+ // If we get in here we got the correct arch, now we just need
+ // to verify the UUID if one was given
+ if (uuid_ptr && *uuid_ptr != module_sp->GetUUID())
+ module_sp.reset();
+ else
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+
+ shared_module_list.ReplaceEquivalent(module_sp);
+ return error;
+ }
+ }
else
+ module_sp.reset();
+
+ if (module_search_paths_ptr)
{
- module_sp.reset (new Module (module_spec));
- // Make sure there are a module and an object file since we can specify
- // a valid file path with an architecture that might not be in that file.
- // By getting the object file we can guarantee that the architecture matches
- if (module_sp)
+ const auto num_directories = module_search_paths_ptr->GetSize();
+ for (size_t idx = 0; idx < num_directories; ++idx)
{
+ auto search_path_spec = module_search_paths_ptr->GetFileSpecAtIndex(idx);
+ if (!search_path_spec.ResolvePath())
+ continue;
+ if (!search_path_spec.Exists() || !search_path_spec.IsDirectory())
+ continue;
+ search_path_spec.AppendPathComponent(module_spec.GetFileSpec().GetFilename().AsCString());
+ if (!search_path_spec.Exists())
+ continue;
+
+ auto resolved_module_spec(module_spec);
+ resolved_module_spec.GetFileSpec() = search_path_spec;
+ module_sp.reset (new Module (resolved_module_spec));
if (module_sp->GetObjectFile())
{
// If we get in here we got the correct arch, now we just need
@@ -998,7 +1030,7 @@ ModuleList::GetSharedModule
*did_create_ptr = true;
shared_module_list.ReplaceEquivalent(module_sp);
- return error;
+ return Error();
}
}
else
@@ -1162,3 +1194,15 @@ ModuleList::LoadScriptingResourcesInTarget (Target *target,
}
return errors.size() == 0;
}
+
+void
+ModuleList::ForEach (std::function <bool (const ModuleSP &module_sp)> const &callback) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ for (const auto &module : m_modules)
+ {
+ // If the callback returns false, then stop iterating and break out
+ if (!callback (module))
+ break;
+ }
+}
diff --git a/source/Core/PluginManager.cpp b/source/Core/PluginManager.cpp
index 95574cb2deaf..e34b7fc3b17d 100644
--- a/source/Core/PluginManager.cpp
+++ b/source/Core/PluginManager.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/PluginManager.h"
#include <limits.h>
@@ -885,6 +883,7 @@ struct LanguageRuntimeInstance
ConstString name;
std::string description;
LanguageRuntimeCreateInstance create_callback;
+ LanguageRuntimeGetCommandObject command_callback;
};
typedef std::vector<LanguageRuntimeInstance> LanguageRuntimeInstances;
@@ -908,7 +907,8 @@ PluginManager::RegisterPlugin
(
const ConstString &name,
const char *description,
- LanguageRuntimeCreateInstance create_callback
+ LanguageRuntimeCreateInstance create_callback,
+ LanguageRuntimeGetCommandObject command_callback
)
{
if (create_callback)
@@ -919,6 +919,7 @@ PluginManager::RegisterPlugin
if (description && description[0])
instance.description = description;
instance.create_callback = create_callback;
+ instance.command_callback = command_callback;
Mutex::Locker locker (GetLanguageRuntimeMutex ());
GetLanguageRuntimeInstances ().push_back (instance);
}
@@ -956,6 +957,16 @@ PluginManager::GetLanguageRuntimeCreateCallbackAtIndex (uint32_t idx)
return NULL;
}
+LanguageRuntimeGetCommandObject
+PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetLanguageRuntimeMutex ());
+ LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances ();
+ if (idx < instances.size())
+ return instances[idx].command_callback;
+ return NULL;
+}
+
LanguageRuntimeCreateInstance
PluginManager::GetLanguageRuntimeCreateCallbackForPluginName (const ConstString &name)
{
diff --git a/source/Core/Scalar.cpp b/source/Core/Scalar.cpp
index 0e9b98dc4ab6..0022c348bfee 100644
--- a/source/Core/Scalar.cpp
+++ b/source/Core/Scalar.cpp
@@ -1900,7 +1900,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b
break;
case lldb::eEncodingUint:
{
- lldb::offset_t offset;
+ lldb::offset_t offset = 0;
switch (byte_size)
{
@@ -1916,7 +1916,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b
break;
case lldb::eEncodingSint:
{
- lldb::offset_t offset;
+ lldb::offset_t offset = 0;
switch (byte_size)
{
@@ -1932,7 +1932,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b
break;
case lldb::eEncodingIEEE754:
{
- lldb::offset_t offset;
+ lldb::offset_t offset = 0;
if (byte_size == sizeof (float))
operator=((float)data.GetFloat(&offset));
diff --git a/source/Core/SearchFilter.cpp b/source/Core/SearchFilter.cpp
index 9c3412a422d0..f54bbe8d4adf 100644
--- a/source/Core/SearchFilter.cpp
+++ b/source/Core/SearchFilter.cpp
@@ -816,7 +816,7 @@ SearchFilterByModuleListAndCU::GetDescription (Stream *s)
}
else if (num_modules > 0)
{
- s->Printf (", modules(%zd) = ", num_modules);
+ s->Printf (", modules(%" PRIu64 ") = ", static_cast<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 ea33a62b775f..9a3f220beb44 100644
--- a/source/Core/Section.cpp
+++ b/source/Core/Section.cpp
@@ -12,6 +12,7 @@
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConvertEnum.h"
#include <limits>
diff --git a/source/Core/SourceManager.cpp b/source/Core/SourceManager.cpp
index 44ab50197c19..324ed34bfaac 100644
--- a/source/Core/SourceManager.cpp
+++ b/source/Core/SourceManager.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/SourceManager.h"
// C Includes
@@ -18,6 +16,7 @@
#include "lldb/Core/DataBuffer.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/Stream.h"
#include "lldb/Symbol/ClangNamespaceDecl.h"
#include "lldb/Symbol/CompileUnit.h"
diff --git a/source/Core/StreamAsynchronousIO.cpp b/source/Core/StreamAsynchronousIO.cpp
index 257982ab8b29..ccfde0c9a011 100644
--- a/source/Core/StreamAsynchronousIO.cpp
+++ b/source/Core/StreamAsynchronousIO.cpp
@@ -7,22 +7,20 @@
//
//===----------------------------------------------------------------------===//
-#include <stdio.h>
+#include "lldb/Core/StreamAsynchronousIO.h"
#include "lldb/lldb-private.h"
-#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/Event.h"
-#include "lldb/Core/StreamAsynchronousIO.h"
+#include "lldb/Core/Debugger.h"
using namespace lldb;
using namespace lldb_private;
-StreamAsynchronousIO::StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type) :
+StreamAsynchronousIO::StreamAsynchronousIO (Debugger &debugger, bool for_stdout) :
Stream (0, 4, eByteOrderBig),
- m_broadcaster (broadcaster),
- m_broadcast_event_type (broadcast_event_type),
- m_accumulated_data ()
+ m_debugger (debugger),
+ m_data (),
+ m_for_stdout (for_stdout)
{
}
@@ -35,19 +33,16 @@ StreamAsynchronousIO::~StreamAsynchronousIO ()
void
StreamAsynchronousIO::Flush ()
{
- if (!m_accumulated_data.empty())
+ if (!m_data.empty())
{
- std::unique_ptr<EventDataBytes> data_bytes_ap (new EventDataBytes);
- // Let's swap the bytes to avoid LARGE string copies.
- data_bytes_ap->SwapBytes (m_accumulated_data);
- EventSP new_event_sp (new Event (m_broadcast_event_type, data_bytes_ap.release()));
- m_broadcaster.BroadcastEvent (new_event_sp);
+ m_debugger.PrintAsync (m_data.data(), m_data.size(), m_for_stdout);
+ m_data = std::move(std::string());
}
}
size_t
StreamAsynchronousIO::Write (const void *s, size_t length)
{
- m_accumulated_data.append ((const char *)s, length);
+ m_data.append ((const char *)s, length);
return length;
}
diff --git a/source/Core/StreamFile.cpp b/source/Core/StreamFile.cpp
index 9f8dd629e3d4..8c9700c6dcba 100644
--- a/source/Core/StreamFile.cpp
+++ b/source/Core/StreamFile.cpp
@@ -54,6 +54,13 @@ StreamFile::StreamFile (const char *path) :
{
}
+StreamFile::StreamFile (const char *path,
+ uint32_t options,
+ uint32_t permissions) :
+ Stream(),
+ m_file(path, options, permissions)
+{
+}
StreamFile::~StreamFile()
{
diff --git a/source/Core/StringList.cpp b/source/Core/StringList.cpp
index d2fa8cfb4a88..4e07ba4a4579 100644
--- a/source/Core/StringList.cpp
+++ b/source/Core/StringList.cpp
@@ -69,6 +69,12 @@ StringList::AppendString (const char *str, size_t str_len)
}
void
+StringList::AppendString(llvm::StringRef str)
+{
+ m_strings.push_back(str.str());
+}
+
+void
StringList::AppendList (const char **strv, int strc)
{
for (int i = 0; i < strc; ++i)
diff --git a/source/Core/StructuredData.cpp b/source/Core/StructuredData.cpp
index 3c43e41f3c94..a2c440948af1 100644
--- a/source/Core/StructuredData.cpp
+++ b/source/Core/StructuredData.cpp
@@ -13,6 +13,8 @@
#include <stdlib.h>
#include <inttypes.h>
+#include "lldb/Core/StreamString.h"
+
using namespace lldb_private;
@@ -296,6 +298,10 @@ StructuredData::ParseJSON (std::string json_text)
{
object_sp = read_json_object (&c);
}
+ else if (*c == '[')
+ {
+ object_sp = read_json_array (&c);
+ }
else
{
// We have bad characters here, this is likely an illegal JSON string.
@@ -350,16 +356,32 @@ StructuredData::Object::GetObjectForDotSeparatedPath (llvm::StringRef path)
}
void
-StructuredData::Array::Dump (Stream &s) const
+StructuredData::Object::DumpToStdout() const
{
- s << "[";
- const size_t arrsize = m_items.size();
- for (size_t i = 0; i < arrsize; ++i)
+ StreamString stream;
+ Dump(stream);
+ printf("%s\n", stream.GetString().c_str());
+}
+
+void
+StructuredData::Array::Dump(Stream &s) const
+{
+ bool first = true;
+ s << "[\n";
+ s.IndentMore();
+ for (const auto &item_sp : m_items)
{
- m_items[i]->Dump(s);
- if (i + 1 < arrsize)
- s << ",";
+ if (first)
+ first = false;
+ else
+ s << ",\n";
+
+ s.Indent();
+ item_sp->Dump(s);
}
+ s.IndentLess();
+ s.EOL();
+ s.Indent();
s << "]";
}
@@ -404,21 +426,22 @@ StructuredData::String::Dump (Stream &s) const
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)
+ bool first = true;
+ s << "{\n";
+ s.IndentMore();
+ for (const auto &pair : m_dict)
{
- if (have_printed_one_elem == false)
- {
- have_printed_one_elem = true;
- }
+ if (first)
+ first = false;
else
- {
- s << ",";
- }
- s << "\"" << iter->first.AsCString() << "\":";
- iter->second->Dump(s);
+ s << ",\n";
+ s.Indent();
+ s << "\"" << pair.first.AsCString() << "\" : ";
+ pair.second->Dump(s);
}
+ s.IndentLess();
+ s.EOL();
+ s.Indent();
s << "}";
}
@@ -427,3 +450,9 @@ StructuredData::Null::Dump (Stream &s) const
{
s << "null";
}
+
+void
+StructuredData::Generic::Dump(Stream &s) const
+{
+ s << "0x" << m_object;
+}
diff --git a/source/Core/UUID.cpp b/source/Core/UUID.cpp
index c1b3eb13d656..88290d137943 100644
--- a/source/Core/UUID.cpp
+++ b/source/Core/UUID.cpp
@@ -234,7 +234,10 @@ UUID::SetFromCString (const char *cstr, uint32_t num_uuid_bytes)
// If we successfully decoded a UUID, return the amount of characters that
// were consumed
if (uuid_byte_idx == num_uuid_bytes)
+ {
+ m_num_uuid_bytes = num_uuid_bytes;
return p - cstr;
+ }
// Else return zero to indicate we were not able to parse a UUID value
return 0;
diff --git a/source/Core/UserSettingsController.cpp b/source/Core/UserSettingsController.cpp
index 63a5dd9ed51f..837ff18721e2 100644
--- a/source/Core/UserSettingsController.cpp
+++ b/source/Core/UserSettingsController.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include <string.h>
#include <algorithm>
@@ -18,6 +16,7 @@
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/OptionValueString.h"
using namespace lldb;
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
index b72e5c3f18c6..8718b37b95e0 100644
--- a/source/Core/ValueObject.cpp
+++ b/source/Core/ValueObject.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/ValueObject.h"
// C Includes
@@ -43,7 +41,6 @@
#include "lldb/Host/Endian.h"
#include "lldb/Interpreter/CommandInterpreter.h"
-#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Symbol/ClangASTContext.h"
@@ -198,7 +195,7 @@ ValueObject::UpdateValueIfNeeded (bool update_format)
bool first_update = IsChecksumEmpty();
- if (m_update_point.NeedsUpdating())
+ if (NeedsUpdating())
{
m_update_point.SetUpdated();
@@ -973,7 +970,7 @@ ValueObject::GetPointeeData (DataExtractor& data,
ExecutionContext exe_ctx (GetExecutionContextRef());
- const uint64_t item_type_size = pointee_or_element_clang_type.GetByteSize(&exe_ctx);
+ const uint64_t item_type_size = pointee_or_element_clang_type.GetByteSize(exe_ctx.GetBestExecutionContextScope());
const uint64_t bytes = item_count * item_type_size;
const uint64_t offset = item_idx * item_type_size;
@@ -1049,10 +1046,13 @@ ValueObject::GetPointeeData (DataExtractor& data,
break;
case eAddressTypeHost:
{
- const uint64_t max_bytes = GetClangType().GetByteSize(&exe_ctx);
+ const uint64_t max_bytes = GetClangType().GetByteSize(exe_ctx.GetBestExecutionContextScope());
if (max_bytes > offset)
{
size_t bytes_read = std::min<uint64_t>(max_bytes - offset, bytes);
+ addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ if (addr == LLDB_INVALID_ADDRESS)
+ break;
heap_buf_ptr->CopyData((uint8_t*)(addr + offset), bytes_read);
data.SetData(data_sp);
return bytes_read;
@@ -1821,13 +1821,19 @@ ValueObject::GetAddressOf (bool scalar_is_load_address, AddressType *address_typ
case Value::eValueTypeLoadAddress:
case Value::eValueTypeFileAddress:
- case Value::eValueTypeHostAddress:
{
if(address_type)
*address_type = m_value.GetValueAddressType ();
return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
}
break;
+ case Value::eValueTypeHostAddress:
+ {
+ if(address_type)
+ *address_type = m_value.GetValueAddressType ();
+ return LLDB_INVALID_ADDRESS;
+ }
+ break;
}
if (address_type)
*address_type = eAddressTypeInvalid;
@@ -2064,6 +2070,21 @@ ValueObject::IsPossibleDynamicType ()
}
bool
+ValueObject::IsRuntimeSupportValue ()
+{
+ Process *process(GetProcessSP().get());
+ if (process)
+ {
+ LanguageRuntime *runtime = process->GetLanguageRuntime(GetObjectRuntimeLanguage());
+ if (!runtime)
+ runtime = process->GetObjCLanguageRuntime();
+ if (runtime)
+ return runtime->IsRuntimeSupportValue(*this);
+ }
+ return false;
+}
+
+bool
ValueObject::IsObjCNil ()
{
const uint32_t mask = eTypeIsObjC | eTypeIsPointer;
@@ -2075,52 +2096,6 @@ ValueObject::IsObjCNil ()
return canReadValue && isZero;
}
-ValueObjectSP
-ValueObject::GetSyntheticArrayMember (size_t index, bool can_create)
-{
- const uint32_t type_info = GetTypeInfo ();
- if (type_info & eTypeIsArray)
- return GetSyntheticArrayMemberFromArray(index, can_create);
-
- if (type_info & eTypeIsPointer)
- return GetSyntheticArrayMemberFromPointer(index, can_create);
-
- return ValueObjectSP();
-
-}
-
-ValueObjectSP
-ValueObject::GetSyntheticArrayMemberFromPointer (size_t index, bool can_create)
-{
- ValueObjectSP synthetic_child_sp;
- if (IsPointerType ())
- {
- char index_str[64];
- 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.
- synthetic_child_sp = GetSyntheticChild (index_const_str);
- if (!synthetic_child_sp)
- {
- ValueObject *synthetic_child;
- // We haven't made a synthetic array member for INDEX yet, so
- // lets make one and cache it for any future reference.
- synthetic_child = CreateChildAtIndex(0, true, index);
-
- // Cache the value if we got one back...
- if (synthetic_child)
- {
- AddSyntheticChild(index_const_str, synthetic_child);
- synthetic_child_sp = synthetic_child->GetSP();
- synthetic_child_sp->SetName(ConstString(index_str));
- synthetic_child_sp->m_is_array_item_for_pointer = true;
- }
- }
- }
- return synthetic_child_sp;
-}
-
// This allows you to create an array member using and index
// that doesn't not fall in the normal bounds of the array.
// Many times structure can be defined as:
@@ -2133,10 +2108,10 @@ ValueObject::GetSyntheticArrayMemberFromPointer (size_t index, bool can_create)
// there are more items in "item_array".
ValueObjectSP
-ValueObject::GetSyntheticArrayMemberFromArray (size_t index, bool can_create)
+ValueObject::GetSyntheticArrayMember (size_t index, bool can_create)
{
ValueObjectSP synthetic_child_sp;
- if (IsArrayType ())
+ if (IsPointerType () || IsArrayType())
{
char index_str[64];
snprintf(index_str, sizeof(index_str), "[%" PRIu64 "]", (uint64_t)index);
@@ -2150,7 +2125,7 @@ ValueObject::GetSyntheticArrayMemberFromArray (size_t index, bool can_create)
// We haven't made a synthetic array member for INDEX yet, so
// lets make one and cache it for any future reference.
synthetic_child = CreateChildAtIndex(0, true, index);
-
+
// Cache the value if we got one back...
if (synthetic_child)
{
@@ -2229,7 +2204,7 @@ ValueObject::GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type
ValueObjectChild *synthetic_child = new ValueObjectChild(*this,
type,
name_const_str,
- type.GetByteSize(&exe_ctx),
+ type.GetByteSize(exe_ctx.GetBestExecutionContextScope()),
offset,
0,
0,
@@ -2272,7 +2247,7 @@ ValueObject::GetSyntheticBase (uint32_t offset, const ClangASTType& type, bool c
ValueObjectChild *synthetic_child = new ValueObjectChild(*this,
type,
name_const_str,
- type.GetByteSize(&exe_ctx),
+ type.GetByteSize(exe_ctx.GetBestExecutionContextScope()),
offset,
0,
0,
@@ -2320,7 +2295,7 @@ ValueObject::GetSyntheticExpressionPathChild(const char* expression, bool can_cr
// lets make one and cache it for any future reference.
synthetic_child_sp = GetValueForExpressionPath(expression,
NULL, NULL, NULL,
- GetValueForExpressionPathOptions().DontAllowSyntheticChildren());
+ GetValueForExpressionPathOptions().SetSyntheticChildrenTraversal(GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None));
// Cache the value if we got one back...
if (synthetic_child_sp.get())
@@ -2851,19 +2826,43 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
*final_result = ValueObject::eExpressionPathEndResultTypePlain;
return child_valobj_sp;
}
- else if (options.m_no_synthetic_children == false) // let's try with synthetic children
+ else
{
- if (root->IsSynthetic())
+ switch (options.m_synthetic_children_traversal)
{
- *first_unparsed = expression_cstr;
- *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchSyntheticChild;
- *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
- return ValueObjectSP();
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None:
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::FromSynthetic:
+ if (root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetNonSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic:
+ if (!root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both:
+ if (root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetNonSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ else
+ {
+ child_valobj_sp = root->GetSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
}
-
- child_valobj_sp = root->GetSyntheticValue();
- if (child_valobj_sp.get())
- child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
}
// if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP,
@@ -2894,19 +2893,43 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
*final_result = ValueObject::eExpressionPathEndResultTypePlain;
continue;
}
- else if (options.m_no_synthetic_children == false) // let's try with synthetic children
+ else
{
- if (root->IsSynthetic())
+ switch (options.m_synthetic_children_traversal)
{
- *first_unparsed = expression_cstr;
- *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
- *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
- return ValueObjectSP();
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None:
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::FromSynthetic:
+ if (root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetNonSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic:
+ if (!root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both:
+ if (root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetNonSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ else
+ {
+ child_valobj_sp = root->GetSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
}
-
- child_valobj_sp = root->GetSyntheticValue(true);
- if (child_valobj_sp)
- child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
}
// if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP,
@@ -2934,7 +2957,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
{
if (!root_clang_type_info.Test(eTypeIsScalar)) // if this is not even a scalar...
{
- if (options.m_no_synthetic_children) // ...only chance left is synthetic
+ if (options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None) // ...only chance left is synthetic
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid;
@@ -3009,7 +3032,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
{
ValueObjectSP child_valobj_sp = root->GetChildAtIndex(index, true);
if (!child_valobj_sp)
- child_valobj_sp = root->GetSyntheticArrayMemberFromArray(index, true);
+ child_valobj_sp = root->GetSyntheticArrayMember(index, true);
if (!child_valobj_sp)
if (root->HasSyntheticValue() && root->GetSyntheticValue()->GetNumChildren() > index)
child_valobj_sp = root->GetSyntheticValue()->GetChildAtIndex(index, true);
@@ -3053,12 +3076,13 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
if (root->GetClangType().GetMinimumLanguage() == eLanguageTypeObjC
&& pointee_clang_type_info.AllClear(eTypeIsPointer)
&& root->HasSyntheticValue()
- && options.m_no_synthetic_children == false)
+ && (options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic ||
+ options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both))
{
root = root->GetSyntheticValue()->GetChildAtIndex(index, true);
}
else
- root = root->GetSyntheticArrayMemberFromPointer(index, true);
+ root = root->GetSyntheticArrayMember(index, true);
if (!root.get())
{
*first_unparsed = expression_cstr;
@@ -3109,7 +3133,8 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
continue;
}
}
- else if (options.m_no_synthetic_children == false)
+ else if (options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic ||
+ options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both)
{
if (root->HasSyntheticValue())
root = root->GetSyntheticValue();
@@ -3401,7 +3426,7 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
}
else
{
- root = root->GetSyntheticArrayMemberFromPointer(index, true);
+ root = root->GetSyntheticArrayMember(index, true);
if (!root.get())
{
*first_unparsed = expression_cstr;
@@ -3535,7 +3560,7 @@ void
ValueObject::LogValueObject (Log *log)
{
if (log)
- return LogValueObject (log, DumpValueObjectOptions::DefaultOptions());
+ return LogValueObject (log, DumpValueObjectOptions(*this));
}
void
@@ -3553,7 +3578,7 @@ ValueObject::LogValueObject (Log *log, const DumpValueObjectOptions& options)
void
ValueObject::Dump (Stream &s)
{
- Dump (s, DumpValueObjectOptions::DefaultOptions());
+ Dump (s, DumpValueObjectOptions(*this));
}
void
@@ -3766,7 +3791,7 @@ ValueObject::AddressOf (Error &error)
const bool scalar_is_load_address = false;
addr_t addr = GetAddressOf (scalar_is_load_address, &address_type);
error.Clear();
- if (addr != LLDB_INVALID_ADDRESS)
+ if (addr != LLDB_INVALID_ADDRESS && address_type != eAddressTypeHost)
{
switch (address_type)
{
@@ -3780,7 +3805,6 @@ ValueObject::AddressOf (Error &error)
case eAddressTypeFile:
case eAddressTypeLoad:
- case eAddressTypeHost:
{
ClangASTType clang_type = GetClangType();
if (clang_type)
@@ -3797,6 +3821,8 @@ ValueObject::AddressOf (Error &error)
}
}
break;
+ default:
+ break;
}
}
else
@@ -3923,9 +3949,8 @@ ValueObject::EvaluationPoint::~EvaluationPoint ()
// exe_scope will be set to the current execution context scope.
bool
-ValueObject::EvaluationPoint::SyncWithProcessState()
+ValueObject::EvaluationPoint::SyncWithProcessState(bool accept_invalid_exe_ctx)
{
-
// Start with the target, if it is NULL, then we're obviously not going to get any further:
const bool thread_and_frame_only_if_stopped = true;
ExecutionContext exe_ctx(m_exe_ctx_ref.Lock(thread_and_frame_only_if_stopped));
@@ -3968,30 +3993,33 @@ ValueObject::EvaluationPoint::SyncWithProcessState()
// That way we'll be sure to return a valid exe_scope.
// If we used to have a thread or a frame but can't find it anymore, then mark ourselves as invalid.
- if (m_exe_ctx_ref.HasThreadRef())
+ if (!accept_invalid_exe_ctx)
{
- ThreadSP thread_sp (m_exe_ctx_ref.GetThreadSP());
- if (thread_sp)
+ if (m_exe_ctx_ref.HasThreadRef())
{
- if (m_exe_ctx_ref.HasFrameRef())
+ ThreadSP thread_sp (m_exe_ctx_ref.GetThreadSP());
+ if (thread_sp)
{
- StackFrameSP frame_sp (m_exe_ctx_ref.GetFrameSP());
- if (!frame_sp)
+ if (m_exe_ctx_ref.HasFrameRef())
{
- // We used to have a frame, but now it is gone
- SetInvalid();
- changed = was_valid;
+ StackFrameSP frame_sp (m_exe_ctx_ref.GetFrameSP());
+ if (!frame_sp)
+ {
+ // We used to have a frame, but now it is gone
+ SetInvalid();
+ changed = was_valid;
+ }
}
}
+ else
+ {
+ // We used to have a thread, but now it is gone
+ SetInvalid();
+ changed = was_valid;
+ }
}
- else
- {
- // We used to have a thread, but now it is gone
- SetInvalid();
- changed = was_valid;
- }
-
}
+
return changed;
}
diff --git a/source/Core/ValueObjectChild.cpp b/source/Core/ValueObjectChild.cpp
index 2b3c8344af8f..c1e45e1f48de 100644
--- a/source/Core/ValueObjectChild.cpp
+++ b/source/Core/ValueObjectChild.cpp
@@ -110,6 +110,14 @@ ValueObjectChild::GetDisplayTypeName()
}
bool
+ValueObjectChild::CanUpdateWithInvalidExecutionContext ()
+{
+ if (m_parent)
+ return m_parent->CanUpdateWithInvalidExecutionContext();
+ return this->ValueObject::CanUpdateWithInvalidExecutionContext();
+}
+
+bool
ValueObjectChild::UpdateValue ()
{
m_error.Clear();
diff --git a/source/Core/ValueObjectConstResult.cpp b/source/Core/ValueObjectConstResult.cpp
index e8b477a74a52..b4e630306469 100644
--- a/source/Core/ValueObjectConstResult.cpp
+++ b/source/Core/ValueObjectConstResult.cpp
@@ -259,7 +259,7 @@ ValueObjectConstResult::GetByteSize()
ExecutionContext exe_ctx(GetExecutionContextRef());
if (m_byte_size == 0)
- SetByteSize(GetClangType().GetByteSize(&exe_ctx));
+ SetByteSize(GetClangType().GetByteSize(exe_ctx.GetBestExecutionContextScope()));
return m_byte_size;
}
diff --git a/source/Core/ValueObjectSyntheticFilter.cpp b/source/Core/ValueObjectSyntheticFilter.cpp
index e266267981b8..867b52016298 100644
--- a/source/Core/ValueObjectSyntheticFilter.cpp
+++ b/source/Core/ValueObjectSyntheticFilter.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/ValueObjectSyntheticFilter.h"
// C Includes
@@ -304,3 +302,15 @@ ValueObjectSynthetic::SetValueFromCString (const char *value_str, Error& error)
{
return m_parent->SetValueFromCString(value_str, error);
}
+
+void
+ValueObjectSynthetic::SetFormat (lldb::Format format)
+{
+ if (m_parent)
+ {
+ m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
+ m_parent->SetFormat(format);
+ }
+ this->ValueObject::SetFormat(format);
+ this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
+}
diff --git a/source/Core/ValueObjectVariable.cpp b/source/Core/ValueObjectVariable.cpp
index ed2aeb3d9634..c86bece42eb8 100644
--- a/source/Core/ValueObjectVariable.cpp
+++ b/source/Core/ValueObjectVariable.cpp
@@ -112,7 +112,7 @@ ValueObjectVariable::GetByteSize()
if (!type.IsValid())
return 0;
- return type.GetByteSize(&exe_ctx);
+ return type.GetByteSize(exe_ctx.GetBestExecutionContextScope());
}
lldb::ValueType
diff --git a/source/DataFormatters/CF.cpp b/source/DataFormatters/CF.cpp
index 483419e5ac3f..6ab9013268bd 100644
--- a/source/DataFormatters/CF.cpp
+++ b/source/DataFormatters/CF.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
diff --git a/source/DataFormatters/CXXFormatterFunctions.cpp b/source/DataFormatters/CXXFormatterFunctions.cpp
index 5aa8289794c1..49eacee42f78 100644
--- a/source/DataFormatters/CXXFormatterFunctions.cpp
+++ b/source/DataFormatters/CXXFormatterFunctions.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/TypeSummary.h"
@@ -29,10 +27,13 @@
#include "lldb/Utility/ProcessStructReader.h"
#include <algorithm>
+
#if __ANDROID_NDK__
#include <sys/types.h>
#endif
+#include "lldb/Host/Time.h"
+
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
@@ -317,7 +318,7 @@ lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Strea
return false;
ClangASTType wchar_clang_type = ClangASTContext::GetBasicType(ast, lldb::eBasicTypeWChar);
- const uint32_t wchar_size = wchar_clang_type.GetBitSize(nullptr);
+ const uint32_t wchar_size = wchar_clang_type.GetBitSize(nullptr); // Safe to pass NULL for exe_scope here
ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(data_addr);
diff --git a/source/DataFormatters/Cocoa.cpp b/source/DataFormatters/Cocoa.cpp
index 137fd4f483cc..28f3d4f1d41b 100644
--- a/source/DataFormatters/Cocoa.cpp
+++ b/source/DataFormatters/Cocoa.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
diff --git a/source/DataFormatters/CoreMedia.cpp b/source/DataFormatters/CoreMedia.cpp
new file mode 100644
index 000000000000..5c33c0b69f72
--- /dev/null
+++ b/source/DataFormatters/CoreMedia.cpp
@@ -0,0 +1,85 @@
+//===-- CoreMedia.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/DataFormatters/CXXFormatterFunctions.h"
+
+#include "lldb/Core/Flags.h"
+#include "lldb/Symbol/ClangASTContext.h"
+
+#include <inttypes.h>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+bool
+lldb_private::formatters::CMTimeSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
+{
+ ClangASTContext *ast_ctx = ClangASTContext::GetASTContext(valobj.GetClangType().GetASTContext());
+ if (!ast_ctx)
+ return false;
+
+ // fetch children by offset to compensate for potential lack of debug info
+ auto int64_ty = ast_ctx->GetIntTypeFromBitSize(64, true);
+ auto int32_ty = ast_ctx->GetIntTypeFromBitSize(32, true);
+
+ auto value_sp(valobj.GetSyntheticChildAtOffset(0, int64_ty, true));
+ auto timescale_sp(valobj.GetSyntheticChildAtOffset(8, int32_ty, true));
+ auto flags_sp(valobj.GetSyntheticChildAtOffset(12, int32_ty, true));
+
+ if (!value_sp || !timescale_sp || !flags_sp)
+ return false;
+
+ auto value = value_sp->GetValueAsUnsigned(0);
+ auto timescale = (int32_t)timescale_sp->GetValueAsUnsigned(0); // the timescale specifies the fraction of a second each unit in the numerator occupies
+ auto flags = Flags(flags_sp->GetValueAsUnsigned(0) & 0x00000000000000FF); // the flags I need sit in the LSB
+
+ const unsigned int FlagPositiveInf = 4;
+ const unsigned int FlagNegativeInf = 8;
+ const unsigned int FlagIndefinite = 16;
+
+ if (flags.AnySet(FlagIndefinite))
+ {
+ stream.Printf("indefinite");
+ return true;
+ }
+
+ if (flags.AnySet(FlagPositiveInf))
+ {
+ stream.Printf("+oo");
+ return true;
+ }
+
+ if (flags.AnySet(FlagNegativeInf))
+ {
+ stream.Printf("-oo");
+ return true;
+ }
+
+ if (timescale == 0)
+ return false;
+
+ switch (timescale)
+ {
+ case 0:
+ return false;
+ case 1:
+ stream.Printf("%" PRId64 " seconds", value);
+ return true;
+ case 2:
+ stream.Printf("%" PRId64 " half seconds", value);
+ return true;
+ case 3:
+ stream.Printf("%" PRId64 " third%sof a second", value, value == 1 ? " " : "s ");
+ return true;
+ default:
+ stream.Printf("%" PRId64 " %" PRId32 "th%sof a second", value, timescale, value == 1 ? " " : "s ");
+ return true;
+ }
+}
diff --git a/source/DataFormatters/DataVisualization.cpp b/source/DataFormatters/DataVisualization.cpp
index 7ef0be50efe0..361254185b31 100644
--- a/source/DataFormatters/DataVisualization.cpp
+++ b/source/DataFormatters/DataVisualization.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/DataVisualization.h"
// C Includes
diff --git a/source/DataFormatters/FormatCache.cpp b/source/DataFormatters/FormatCache.cpp
index aaa4bc1f958a..748c6d80fbd2 100644
--- a/source/DataFormatters/FormatCache.cpp
+++ b/source/DataFormatters/FormatCache.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
// C++ Includes
diff --git a/source/DataFormatters/FormatManager.cpp b/source/DataFormatters/FormatManager.cpp
index ae52b3309ed8..47456ba5c45b 100644
--- a/source/DataFormatters/FormatManager.cpp
+++ b/source/DataFormatters/FormatManager.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/FormatManager.h"
// C Includes
@@ -18,7 +16,6 @@
#include "lldb/Core/Debugger.h"
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
-#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
#include "llvm/ADT/STLExtras.h"
@@ -477,7 +474,7 @@ FormatManager::GetValidatorForType (lldb::TypeNameSpecifierImplSP type_sp)
lldb::TypeCategoryImplSP
FormatManager::GetCategory (const ConstString& category_name,
- bool can_create)
+ bool can_create)
{
if (!category_name)
return GetCategory(m_default_category_name);
@@ -665,7 +662,8 @@ FormatManager::GetFormat (ValueObject& valobj,
log->Printf("[FormatManager::GetFormat] Search failed. Giving hardcoded a chance.");
retval = GetHardcodedFormat(valobj, use_dynamic);
}
- else if (valobj_type)
+
+ if (valobj_type && (!retval || !retval->NonCacheable()))
{
if (log)
log->Printf("[FormatManager::GetFormat] Caching %p for type %s",
@@ -722,7 +720,8 @@ FormatManager::GetSummaryFormat (ValueObject& valobj,
log->Printf("[FormatManager::GetSummaryFormat] Search failed. Giving hardcoded a chance.");
retval = GetHardcodedSummaryFormat(valobj, use_dynamic);
}
- else if (valobj_type)
+
+ if (valobj_type && (!retval || !retval->NonCacheable()))
{
if (log)
log->Printf("[FormatManager::GetSummaryFormat] Caching %p for type %s",
@@ -780,7 +779,8 @@ FormatManager::GetSyntheticChildren (ValueObject& valobj,
log->Printf("[FormatManager::GetSyntheticChildren] Search failed. Giving hardcoded a chance.");
retval = GetHardcodedSyntheticChildren(valobj, use_dynamic);
}
- else if (valobj_type)
+
+ if (valobj_type && (!retval || !retval->NonCacheable()))
{
if (log)
log->Printf("[FormatManager::GetSyntheticChildren] Caching %p for type %s",
@@ -825,7 +825,8 @@ FormatManager::GetValidator (ValueObject& valobj,
log->Printf("[FormatManager::GetValidator] Search failed. Giving hardcoded a chance.");
retval = GetHardcodedValidator(valobj, use_dynamic);
}
- else if (valobj_type)
+
+ if (valobj_type && (!retval || !retval->NonCacheable()))
{
if (log)
log->Printf("[FormatManager::GetValidator] Caching %p for type %s",
@@ -866,6 +867,7 @@ FormatManager::FormatManager() :
m_coreservices_category_name(ConstString("CoreServices")),
m_vectortypes_category_name(ConstString("VectorTypes")),
m_appkit_category_name(ConstString("AppKit")),
+ m_coremedia_category_name(ConstString("CoreMedia")),
m_hardcoded_formats(),
m_hardcoded_summaries(),
m_hardcoded_synthetics(),
@@ -876,6 +878,7 @@ FormatManager::FormatManager() :
LoadLibStdcppFormatters();
LoadLibcxxFormatters();
LoadObjCFormatters();
+ LoadCoreMediaFormatters();
LoadHardcodedFormatters();
EnableCategory(m_objc_category_name,TypeCategoryMap::Last);
@@ -883,6 +886,7 @@ FormatManager::FormatManager() :
EnableCategory(m_appkit_category_name,TypeCategoryMap::Last);
EnableCategory(m_coreservices_category_name,TypeCategoryMap::Last);
EnableCategory(m_coregraphics_category_name,TypeCategoryMap::Last);
+ EnableCategory(m_coremedia_category_name,TypeCategoryMap::Last);
EnableCategory(m_gnu_cpp_category_name,TypeCategoryMap::Last);
EnableCategory(m_libcxx_category_name,TypeCategoryMap::Last);
EnableCategory(m_vectortypes_category_name,TypeCategoryMap::Last);
@@ -1152,19 +1156,23 @@ FormatManager::LoadSystemFormatters()
.SetShowMembersOneLiner(false)
.SetHideItemNames(false);
+ TypeSummaryImpl::Flags string_array_flags;
+ string_array_flags.SetCascades(false)
+ .SetSkipPointers(true)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(true)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
lldb::TypeSummaryImplSP string_format(new StringSummaryFormat(string_flags, "${var%s}"));
- lldb::TypeSummaryImplSP string_array_format(new StringSummaryFormat(TypeSummaryImpl::Flags().SetCascades(false)
- .SetSkipPointers(true)
- .SetSkipReferences(false)
- .SetDontShowChildren(true)
- .SetDontShowValue(true)
- .SetShowMembersOneLiner(false)
- .SetHideItemNames(false),
+ lldb::TypeSummaryImplSP string_array_format(new StringSummaryFormat(string_array_flags,
"${var%s}"));
lldb::RegularExpressionSP any_size_char_arr(new RegularExpression("char \\[[0-9]+\\]"));
+ lldb::RegularExpressionSP any_size_wchar_arr(new RegularExpression("wchar_t \\[[0-9]+\\]"));
TypeCategoryImpl::SharedPointer sys_category_sp = GetCategory(m_system_category_name);
@@ -1190,6 +1198,7 @@ FormatManager::LoadSystemFormatters()
AddCXXSummary(sys_category_sp, lldb_private::formatters::Char32StringSummaryProvider, "char32_t * summary provider", ConstString("char32_t *"), string_flags);
AddCXXSummary(sys_category_sp, lldb_private::formatters::WCharStringSummaryProvider, "wchar_t * summary provider", ConstString("wchar_t *"), string_flags);
+ AddCXXSummary(sys_category_sp, lldb_private::formatters::WCharStringSummaryProvider, "wchar_t * summary provider", ConstString("wchar_t \\[[0-9]+\\]"), string_array_flags, true);
AddCXXSummary(sys_category_sp, lldb_private::formatters::Char16StringSummaryProvider, "unichar * summary provider", ConstString("unichar *"), string_flags);
@@ -1212,7 +1221,6 @@ FormatManager::LoadSystemFormatters()
fourchar_flags.SetCascades(true).SetSkipPointers(true).SetSkipReferences(true);
AddFormat(sys_category_sp, lldb::eFormatOSType, ConstString("FourCharCode"), fourchar_flags);
-
#endif
}
@@ -1563,6 +1571,25 @@ FormatManager::LoadObjCFormatters()
}
void
+FormatManager::LoadCoreMediaFormatters()
+{
+ TypeSummaryImpl::Flags cm_flags;
+ cm_flags.SetCascades(true)
+ .SetDontShowChildren(false)
+ .SetDontShowValue(false)
+ .SetHideItemNames(false)
+ .SetShowMembersOneLiner(false)
+ .SetSkipPointers(false)
+ .SetSkipReferences(false);
+
+ TypeCategoryImpl::SharedPointer cm_category_sp = GetCategory(m_coremedia_category_name);
+
+#ifndef LLDB_DISABLE_PYTHON
+ AddCXXSummary(cm_category_sp, lldb_private::formatters::CMTimeSummaryProvider, "CMTime summary provider", ConstString("CMTime"), cm_flags);
+#endif // LLDB_DISABLE_PYTHON
+}
+
+void
FormatManager::LoadHardcodedFormatters()
{
{
@@ -1584,6 +1611,20 @@ FormatManager::LoadHardcodedFormatters()
}
{
// insert code to load synthetics here
+ m_hardcoded_synthetics.push_back(
+ [](lldb_private::ValueObject& valobj,
+ lldb::DynamicValueType,
+ FormatManager& fmt_mgr) -> SyntheticChildren::SharedPointer {
+ static CXXSyntheticChildren::SharedPointer formatter_sp(new CXXSyntheticChildren(SyntheticChildren::Flags().SetCascades(true).SetSkipPointers(true).SetSkipReferences(true).SetNonCacheable(true),
+ "vector_type synthetic children",
+ lldb_private::formatters::VectorTypeSyntheticFrontEndCreator));
+ if (valobj.GetClangType().IsVectorType(nullptr, nullptr))
+ {
+ if (fmt_mgr.GetCategory(fmt_mgr.m_vectortypes_category_name)->IsEnabled())
+ return formatter_sp;
+ }
+ return nullptr;
+ });
}
{
// insert code to load validators here
diff --git a/source/DataFormatters/LibCxx.cpp b/source/DataFormatters/LibCxx.cpp
index 728ad84341f0..a04b4ff6b8c7 100644
--- a/source/DataFormatters/LibCxx.cpp
+++ b/source/DataFormatters/LibCxx.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
@@ -266,7 +264,7 @@ lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update()
NULL,
NULL,
NULL,
- ValueObject::GetValueForExpressionPathOptions().DontCheckDotVsArrowSyntax().DontAllowSyntheticChildren(),
+ ValueObject::GetValueForExpressionPathOptions().DontCheckDotVsArrowSyntax().SetSyntheticChildrenTraversal(ValueObject::GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None),
NULL).get();
return false;
diff --git a/source/DataFormatters/LibCxxInitializerList.cpp b/source/DataFormatters/LibCxxInitializerList.cpp
index 91f1f90507a7..0dcef981e5e5 100644
--- a/source/DataFormatters/LibCxxInitializerList.cpp
+++ b/source/DataFormatters/LibCxxInitializerList.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/ConstString.h"
diff --git a/source/DataFormatters/LibCxxList.cpp b/source/DataFormatters/LibCxxList.cpp
index 5bb6ce07480f..f3e07fe7a017 100644
--- a/source/DataFormatters/LibCxxList.cpp
+++ b/source/DataFormatters/LibCxxList.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
diff --git a/source/DataFormatters/LibCxxMap.cpp b/source/DataFormatters/LibCxxMap.cpp
index 82e747e2db08..2ff623284845 100644
--- a/source/DataFormatters/LibCxxMap.cpp
+++ b/source/DataFormatters/LibCxxMap.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
diff --git a/source/DataFormatters/LibCxxUnorderedMap.cpp b/source/DataFormatters/LibCxxUnorderedMap.cpp
index da2a88966f5e..43669803195e 100644
--- a/source/DataFormatters/LibCxxUnorderedMap.cpp
+++ b/source/DataFormatters/LibCxxUnorderedMap.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
diff --git a/source/DataFormatters/LibCxxVector.cpp b/source/DataFormatters/LibCxxVector.cpp
index d0e6be486d65..6ccb732f6779 100644
--- a/source/DataFormatters/LibCxxVector.cpp
+++ b/source/DataFormatters/LibCxxVector.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/ConstString.h"
diff --git a/source/DataFormatters/LibStdcpp.cpp b/source/DataFormatters/LibStdcpp.cpp
index b8f031ceeb2f..2b3bcb58afac 100644
--- a/source/DataFormatters/LibStdcpp.cpp
+++ b/source/DataFormatters/LibStdcpp.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
@@ -25,175 +23,6 @@ using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
-lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::LibstdcppVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
-SyntheticChildrenFrontEnd(*valobj_sp.get()),
-m_exe_ctx_ref(),
-m_count(0),
-m_base_data_address(0),
-m_options()
-{
- if (valobj_sp)
- Update();
- m_options.SetCoerceToId(false);
- m_options.SetUnwindOnError(true);
- m_options.SetKeepInMemory(true);
- m_options.SetUseDynamic(lldb::eDynamicCanRunTarget);
-}
-
-size_t
-lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::CalculateNumChildren ()
-{
- return m_count;
-}
-
-lldb::ValueObjectSP
-lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx)
-{
- if (idx >= m_count)
- return ValueObjectSP();
- if (m_base_data_address == 0 || m_count == 0)
- return ValueObjectSP();
- size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
- size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
- lldb::addr_t byte_location = m_base_data_address + byte_idx;
- ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
- if (!process_sp)
- return ValueObjectSP();
- uint8_t byte = 0;
- uint8_t mask = 0;
- Error err;
- size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
- if (err.Fail() || bytes_read == 0)
- return ValueObjectSP();
- switch (bit_index)
- {
- case 0:
- mask = 1; break;
- case 1:
- mask = 2; break;
- case 2:
- mask = 4; break;
- case 3:
- mask = 8; break;
- case 4:
- mask = 16; break;
- case 5:
- mask = 32; break;
- case 6:
- mask = 64; break;
- case 7:
- mask = 128; break;
- default:
- return ValueObjectSP();
- }
- bool bit_set = ((byte & mask) != 0);
- Target& target(process_sp->GetTarget());
- ValueObjectSP retval_sp;
- if (bit_set)
- target.EvaluateExpression("(bool)true", NULL, retval_sp);
- else
- target.EvaluateExpression("(bool)false", NULL, retval_sp);
- StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- if (retval_sp)
- retval_sp->SetName(ConstString(name.GetData()));
- return retval_sp;
-}
-
-/*((std::vector<std::allocator<bool> >) vBool = {
- (std::_Bvector_base<std::allocator<bool> >) std::_Bvector_base<std::allocator<bool> > = {
- (std::_Bvector_base<std::allocator<bool> >::_Bvector_impl) _M_impl = {
- (std::_Bit_iterator) _M_start = {
- (std::_Bit_iterator_base) std::_Bit_iterator_base = {
- (_Bit_type *) _M_p = 0x0016b160
- (unsigned int) _M_offset = 0
- }
- }
- (std::_Bit_iterator) _M_finish = {
- (std::_Bit_iterator_base) std::_Bit_iterator_base = {
- (_Bit_type *) _M_p = 0x0016b16c
- (unsigned int) _M_offset = 16
- }
- }
- (_Bit_type *) _M_end_of_storage = 0x0016b170
- }
- }
- }
- */
-
-bool
-lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::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 m_impl_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_impl"), true));
- if (!m_impl_sp)
- return false;
-
- ValueObjectSP m_start_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_start"), true));
- ValueObjectSP m_finish_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_finish"), true));
-
- ValueObjectSP start_p_sp, finish_p_sp, finish_offset_sp;
-
- if (!m_start_sp || !m_finish_sp)
- return false;
-
- start_p_sp = m_start_sp->GetChildMemberWithName(ConstString("_M_p"), true);
- finish_p_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_p"), true);
- finish_offset_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_offset"), true);
-
- if (!start_p_sp || !finish_offset_sp || !finish_p_sp)
- return false;
-
- m_base_data_address = start_p_sp->GetValueAsUnsigned(0);
- if (!m_base_data_address)
- return false;
-
- lldb::addr_t end_data_address(finish_p_sp->GetValueAsUnsigned(0));
- if (!end_data_address)
- return false;
-
- if (end_data_address < m_base_data_address)
- return false;
- else
- m_count = finish_offset_sp->GetValueAsUnsigned(0) + (end_data_address-m_base_data_address)*8;
-
- return true;
-}
-
-bool
-lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::MightHaveChildren ()
-{
- return true;
-}
-
-size_t
-lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
-{
- if (!m_count || !m_base_data_address)
- return UINT32_MAX;
- const char* item_name = name.GetCString();
- uint32_t idx = ExtractIndexFromString(item_name);
- if (idx < UINT32_MAX && idx >= CalculateNumChildren())
- return UINT32_MAX;
- return idx;
-}
-
-lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::~LibstdcppVectorBoolSyntheticFrontEnd ()
-{}
-
-SyntheticChildrenFrontEnd*
-lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
-{
- if (!valobj_sp)
- return NULL;
- return (new LibstdcppVectorBoolSyntheticFrontEnd(valobj_sp));
-}
-
/*
(std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) ibeg = {
(_Base_ptr) _M_node = 0x0000000100103910 {
diff --git a/source/DataFormatters/NSArray.cpp b/source/DataFormatters/NSArray.cpp
index e242155f4fef..640982efdb3c 100644
--- a/source/DataFormatters/NSArray.cpp
+++ b/source/DataFormatters/NSArray.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
diff --git a/source/DataFormatters/NSDictionary.cpp b/source/DataFormatters/NSDictionary.cpp
index fdac05192c46..30bc3acfbec7 100644
--- a/source/DataFormatters/NSDictionary.cpp
+++ b/source/DataFormatters/NSDictionary.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
diff --git a/source/DataFormatters/NSIndexPath.cpp b/source/DataFormatters/NSIndexPath.cpp
index ee9583ef4cc1..363bd5c0527e 100644
--- a/source/DataFormatters/NSIndexPath.cpp
+++ b/source/DataFormatters/NSIndexPath.cpp
@@ -47,7 +47,7 @@ public:
virtual bool
Update()
{
- m_impl.m_mode = Mode::Invalid;
+ m_impl.Clear();
m_ast_ctx = ClangASTContext::GetASTContext(m_backend.GetClangType().GetASTContext());
if (!m_ast_ctx)
@@ -76,8 +76,8 @@ public:
if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload))
{
- m_impl.m_mode = Mode::Inlined;
m_impl.m_inlined.SetIndexes(payload, *process_sp);
+ m_impl.m_mode = Mode::Inlined;
}
else
{
@@ -191,104 +191,133 @@ protected:
}
struct InlinedIndexes {
- public:
- void SetIndexes(uint64_t value, Process& p)
- {
- m_indexes = value;
- _lengthForInlinePayload(p.GetAddressByteSize());
- m_process = &p;
- }
-
- size_t
- GetNumIndexes ()
- {
- return m_count;
- }
-
- lldb::ValueObjectSP
- GetIndexAtIndex (size_t idx, const ClangASTType& desired_type)
- {
- std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
- if (!value.second)
- return nullptr;
- Value v;
- if (m_ptr_size == 8)
- {
- Scalar scalar( (unsigned long long)value.first );
- v = Value(scalar);
- }
- else
- {
- Scalar scalar( (unsigned int)value.first );
- v = Value(scalar);
- }
- v.SetClangType(desired_type);
- StreamString idx_name;
- idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- return ValueObjectConstResult::Create(m_process, v, ConstString(idx_name.GetData()));
- }
-
- private:
- uint64_t m_indexes;
- size_t m_count;
- uint32_t m_ptr_size;
- Process *m_process;
-
- // cfr. Foundation for the details of this code
- size_t _lengthForInlinePayload(uint32_t ptr_size) {
- m_ptr_size = ptr_size;
- if (m_ptr_size == 8)
- m_count = ((m_indexes >> 3) & 0x7);
- else
- m_count = ((m_indexes >> 3) & 0x3);
- return m_count;
- }
-
- std::pair<uint64_t, bool>
- _indexAtPositionForInlinePayload(size_t pos) {
- if (m_ptr_size == 8)
- {
- switch (pos) {
- case 5: return {((m_indexes >> 51) & 0x1ff),true};
- case 4: return {((m_indexes >> 42) & 0x1ff),true};
- case 3: return {((m_indexes >> 33) & 0x1ff),true};
- case 2: return {((m_indexes >> 24) & 0x1ff),true};
- case 1: return {((m_indexes >> 15) & 0x1ff),true};
- case 0: return {((m_indexes >> 6) & 0x1ff),true};
- }
- }
- else
- {
- switch (pos) {
- case 2: return {((m_indexes >> 23) & 0x1ff),true};
- case 1: return {((m_indexes >> 14) & 0x1ff),true};
- case 0: return {((m_indexes >> 5) & 0x1ff),true};
- }
- }
- return {0,false};
- }
+ public:
+ void SetIndexes(uint64_t value, Process& p)
+ {
+ m_indexes = value;
+ _lengthForInlinePayload(p.GetAddressByteSize());
+ m_process = &p;
+ }
+
+ size_t
+ GetNumIndexes ()
+ {
+ return m_count;
+ }
+
+ lldb::ValueObjectSP
+ GetIndexAtIndex (size_t idx, const ClangASTType& desired_type)
+ {
+ std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
+ if (!value.second)
+ return nullptr;
+
+ Value v;
+ if (m_ptr_size == 8)
+ {
+ Scalar scalar( (unsigned long long)value.first );
+ v = Value(scalar);
+ }
+ else
+ {
+ Scalar scalar( (unsigned int)value.first );
+ v = Value(scalar);
+ }
+
+ v.SetClangType(desired_type);
- };
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+
+ return ValueObjectConstResult::Create(m_process, v, ConstString(idx_name.GetData()));
+ }
+
+ void
+ Clear ()
+ {
+ m_indexes = 0;
+ m_count = 0;
+ m_ptr_size = 0;
+ m_process = nullptr;
+ }
+
+ private:
+ uint64_t m_indexes;
+ size_t m_count;
+ uint32_t m_ptr_size;
+ Process *m_process;
+
+ // cfr. Foundation for the details of this code
+ size_t _lengthForInlinePayload(uint32_t ptr_size) {
+ m_ptr_size = ptr_size;
+ if (m_ptr_size == 8)
+ m_count = ((m_indexes >> 3) & 0x7);
+ else
+ m_count = ((m_indexes >> 3) & 0x3);
+ return m_count;
+ }
+
+ std::pair<uint64_t, bool>
+ _indexAtPositionForInlinePayload(size_t pos)
+ {
+ if (m_ptr_size == 8)
+ {
+ switch (pos) {
+ case 5: return {((m_indexes >> 51) & 0x1ff),true};
+ case 4: return {((m_indexes >> 42) & 0x1ff),true};
+ case 3: return {((m_indexes >> 33) & 0x1ff),true};
+ case 2: return {((m_indexes >> 24) & 0x1ff),true};
+ case 1: return {((m_indexes >> 15) & 0x1ff),true};
+ case 0: return {((m_indexes >> 6) & 0x1ff),true};
+ }
+ }
+ else
+ {
+ switch (pos) {
+ case 2: return {((m_indexes >> 23) & 0x1ff),true};
+ case 1: return {((m_indexes >> 14) & 0x1ff),true};
+ case 0: return {((m_indexes >> 5) & 0x1ff),true};
+ }
+ }
+ return {0,false};
+ }
+
+ };
struct OutsourcedIndexes {
- ValueObject *m_indexes;
- size_t m_count;
-
- lldb::ValueObjectSP
- GetIndexAtIndex (size_t idx)
- {
- if (m_indexes)
- {
- ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMemberFromPointer(idx, true));
- return index_sp;
- }
- return nullptr;
- }
- };
+ ValueObject *m_indexes;
+ size_t m_count;
+
+ lldb::ValueObjectSP
+ GetIndexAtIndex (size_t idx)
+ {
+ if (m_indexes)
+ {
+ ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
+ return index_sp;
+ }
+ return nullptr;
+ }
+
+ void
+ Clear ()
+ {
+ m_indexes = nullptr;
+ m_count = 0;
+ }
+ };
union {
- struct InlinedIndexes m_inlined;
- struct OutsourcedIndexes m_outsourced;
+ struct InlinedIndexes m_inlined;
+ struct OutsourcedIndexes m_outsourced;
};
+
+ void
+ Clear ()
+ {
+ m_mode = Mode::Invalid;
+ m_inlined.Clear();
+ m_outsourced.Clear();
+ }
} m_impl;
uint32_t m_ptr_size;
diff --git a/source/DataFormatters/NSSet.cpp b/source/DataFormatters/NSSet.cpp
index 194d1bd29ea1..116904ce99b4 100644
--- a/source/DataFormatters/NSSet.cpp
+++ b/source/DataFormatters/NSSet.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
diff --git a/source/DataFormatters/StringPrinter.cpp b/source/DataFormatters/StringPrinter.cpp
index 3af5931ad716..a011cd553d0c 100644
--- a/source/DataFormatters/StringPrinter.cpp
+++ b/source/DataFormatters/StringPrinter.cpp
@@ -181,12 +181,13 @@ GetPrintableImpl<StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end
break;
default:
if (isprint(*buffer))
- retval = {buffer,1};
+ retval = {buffer,1};
else
{
- retval = { new uint8_t[5],4,[] (const uint8_t* c) {delete[] c;} };
- sprintf((char*)retval.GetBytes(),"\\x%02x",*buffer);
- break;
+ uint8_t* data = new uint8_t[5];
+ sprintf((char*)data,"\\x%02x",*buffer);
+ retval = {data, 4, [] (const uint8_t* c) {delete[] c;} };
+ break;
}
}
@@ -288,8 +289,9 @@ GetPrintableImpl<StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end,
retval = {buffer,utf8_encoded_len};
else
{
- retval = { new uint8_t[11],10,[] (const uint8_t* c) {delete[] c;} };
- sprintf((char*)retval.GetBytes(),"\\U%08x",codepoint);
+ uint8_t* data = new uint8_t[11];
+ sprintf((char*)data,"\\U%08x",codepoint);
+ retval = { data,10,[] (const uint8_t* c) {delete[] c;} };
break;
}
}
@@ -352,8 +354,8 @@ DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType
sourceSize = bufferSPSize/(origin_encoding / 4);
}
- SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart();
- SourceDataType *data_end_ptr = data_ptr + sourceSize;
+ const SourceDataType *data_ptr = (const SourceDataType*)data.GetDataStart();
+ const SourceDataType *data_end_ptr = data_ptr + sourceSize;
while (data_ptr < data_end_ptr)
{
@@ -365,7 +367,7 @@ DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType
data_ptr++;
}
- data_ptr = (SourceDataType*)data.GetDataStart();
+ data_ptr = (const SourceDataType*)data.GetDataStart();
lldb::DataBufferSP utf8_data_buffer_sp;
UTF8* utf8_data_ptr = nullptr;
@@ -376,7 +378,7 @@ DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType
utf8_data_buffer_sp.reset(new DataBufferHeap(4*bufferSPSize,0));
utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes();
utf8_data_end_ptr = utf8_data_ptr + utf8_data_buffer_sp->GetByteSize();
- ConvertFunction ( (const SourceDataType**)&data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion );
+ ConvertFunction ( &data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion );
utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr
}
else
@@ -449,7 +451,6 @@ ReadStringAndDumpToStream<StringElementType::ASCII> (ReadStringAndDumpToStreamOp
{
assert(options.GetStream() && "need a Stream to print the string to");
Error my_error;
- size_t my_data_read;
ProcessSP process_sp(options.GetProcessSP());
@@ -467,7 +468,7 @@ ReadStringAndDumpToStream<StringElementType::ASCII> (ReadStringAndDumpToStreamOp
lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0));
- my_data_read = process_sp->ReadCStringFromMemory(options.GetLocation(), (char*)buffer_sp->GetBytes(), size, my_error);
+ process_sp->ReadCStringFromMemory(options.GetLocation(), (char*)buffer_sp->GetBytes(), size, my_error);
if (my_error.Fail())
return false;
@@ -555,7 +556,7 @@ ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options,
sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
needs_zero_terminator = true;
}
- else
+ else if (!options.GetIgnoreMaxLength())
sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary());
const int bufferSPSize = sourceSize * type_width;
@@ -568,11 +569,10 @@ ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options,
Error error;
char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes());
- size_t data_read = 0;
if (needs_zero_terminator)
- data_read = process_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width);
+ process_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width);
else
- data_read = process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error);
+ process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error);
if (error.Fail())
{
diff --git a/source/DataFormatters/TypeCategory.cpp b/source/DataFormatters/TypeCategory.cpp
index 3df6884fe679..b05cea55ff51 100644
--- a/source/DataFormatters/TypeCategory.cpp
+++ b/source/DataFormatters/TypeCategory.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/TypeCategory.h"
// C Includes
diff --git a/source/DataFormatters/TypeCategoryMap.cpp b/source/DataFormatters/TypeCategoryMap.cpp
index ae34d0339011..96b9e6df8a47 100644
--- a/source/DataFormatters/TypeCategoryMap.cpp
+++ b/source/DataFormatters/TypeCategoryMap.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/DataFormatters/TypeCategoryMap.h"
#include "lldb/DataFormatters/FormatClasses.h"
diff --git a/source/DataFormatters/TypeFormat.cpp b/source/DataFormatters/TypeFormat.cpp
index f07d8127d2b9..c4a65fea7da5 100644
--- a/source/DataFormatters/TypeFormat.cpp
+++ b/source/DataFormatters/TypeFormat.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
// C++ Includes
@@ -22,6 +20,7 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
+#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/DataFormatters/TypeFormat.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/ClangASTType.h"
diff --git a/source/DataFormatters/TypeSummary.cpp b/source/DataFormatters/TypeSummary.cpp
index 4c9cd582e642..fa06f297f829 100644
--- a/source/DataFormatters/TypeSummary.cpp
+++ b/source/DataFormatters/TypeSummary.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
// C++ Includes
diff --git a/source/DataFormatters/TypeSynthetic.cpp b/source/DataFormatters/TypeSynthetic.cpp
index b150b2bb6ee3..5bd8d30e4873 100644
--- a/source/DataFormatters/TypeSynthetic.cpp
+++ b/source/DataFormatters/TypeSynthetic.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
// C++ Includes
@@ -23,7 +21,7 @@
#include "lldb/Core/StreamString.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Interpreter/CommandInterpreter.h"
-#include "lldb/Interpreter/ScriptInterpreterPython.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
@@ -196,7 +194,7 @@ ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex (size_t idx)
bool
ScriptedSyntheticChildren::FrontEnd::IsValid ()
{
- return m_wrapper_sp.get() != nullptr && m_wrapper_sp->operator bool() && m_interpreter != nullptr;
+ return (m_wrapper_sp && m_wrapper_sp->IsValid() && m_interpreter);
}
size_t
diff --git a/source/DataFormatters/ValueObjectPrinter.cpp b/source/DataFormatters/ValueObjectPrinter.cpp
index 5560ce2971e7..7c794ee2ddac 100644
--- a/source/DataFormatters/ValueObjectPrinter.cpp
+++ b/source/DataFormatters/ValueObjectPrinter.cpp
@@ -21,6 +21,28 @@
using namespace lldb;
using namespace lldb_private;
+DumpValueObjectOptions::DumpValueObjectOptions (ValueObject& valobj) :
+DumpValueObjectOptions()
+{
+ m_use_dynamic = valobj.GetDynamicValueType();
+ m_use_synthetic = valobj.IsSynthetic();
+}
+
+ValueObjectPrinter::ValueObjectPrinter (ValueObject* valobj,
+ Stream* s)
+{
+ if (valobj)
+ {
+ DumpValueObjectOptions options(*valobj);
+ Init (valobj,s,options,options.m_max_ptr_depth,0);
+ }
+ else
+ {
+ DumpValueObjectOptions options;
+ Init (valobj,s,options,options.m_max_ptr_depth,0);
+ }
+}
+
ValueObjectPrinter::ValueObjectPrinter (ValueObject* valobj,
Stream* s,
const DumpValueObjectOptions& options)
@@ -631,7 +653,11 @@ ValueObjectPrinter::PrintChildrenIfNeeded (bool value_printed,
uint32_t curr_ptr_depth = m_ptr_depth;
bool print_children = ShouldPrintChildren (is_failed_description,curr_ptr_depth);
- bool print_oneline = (curr_ptr_depth > 0 || options.m_show_types || !options.m_allow_oneliner_mode) ? false : DataVisualization::ShouldPrintAsOneLiner(*m_valobj);
+ bool print_oneline = (curr_ptr_depth > 0 ||
+ options.m_show_types ||
+ !options.m_allow_oneliner_mode ||
+ options.m_flat_output ||
+ options.m_show_location) ? false : DataVisualization::ShouldPrintAsOneLiner(*m_valobj);
if (print_children)
{
diff --git a/source/DataFormatters/VectorType.cpp b/source/DataFormatters/VectorType.cpp
new file mode 100644
index 000000000000..57bf696ba4fa
--- /dev/null
+++ b/source/DataFormatters/VectorType.cpp
@@ -0,0 +1,276 @@
+//===-- VectorType.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/DataFormatters/CXXFormatterFunctions.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTType.h"
+
+#include "lldb/Utility/LLDBAssert.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+static ClangASTType
+GetClangTypeForFormat (lldb::Format format,
+ ClangASTType element_type,
+ ClangASTContext *ast_ctx)
+{
+ lldbassert(ast_ctx && "ast_ctx needs to be not NULL");
+
+ switch (format)
+ {
+ case lldb::eFormatAddressInfo:
+ case lldb::eFormatPointer:
+ return ast_ctx->GetPointerSizedIntType(false);
+
+ case lldb::eFormatBoolean:
+ return ast_ctx->GetBasicType(lldb::eBasicTypeBool);
+
+ case lldb::eFormatBytes:
+ case lldb::eFormatBytesWithASCII:
+ case lldb::eFormatChar:
+ case lldb::eFormatCharArray:
+ case lldb::eFormatCharPrintable:
+ return ast_ctx->GetBasicType(lldb::eBasicTypeChar);
+
+ case lldb::eFormatComplex /* lldb::eFormatComplexFloat */:
+ return ast_ctx->GetBasicType(lldb::eBasicTypeFloatComplex);
+
+ case lldb::eFormatCString:
+ return ast_ctx->GetBasicType(lldb::eBasicTypeChar).GetPointerType();
+
+ case lldb::eFormatFloat:
+ return ast_ctx->GetBasicType(lldb::eBasicTypeFloat);
+
+ case lldb::eFormatHex:
+ case lldb::eFormatHexUppercase:
+ case lldb::eFormatOctal:
+ return ast_ctx->GetBasicType(lldb::eBasicTypeInt);
+
+ case lldb::eFormatHexFloat:
+ return ast_ctx->GetBasicType(lldb::eBasicTypeFloat);
+
+ case lldb::eFormatUnicode16:
+ case lldb::eFormatUnicode32:
+
+ case lldb::eFormatUnsigned:
+ return ast_ctx->GetBasicType(lldb::eBasicTypeUnsignedInt);
+
+ case lldb::eFormatVectorOfChar:
+ return ast_ctx->GetBasicType(lldb::eBasicTypeChar);
+
+ case lldb::eFormatVectorOfFloat32:
+ return ast_ctx->GetFloatTypeFromBitSize(32);
+
+ case lldb::eFormatVectorOfFloat64:
+ return ast_ctx->GetFloatTypeFromBitSize(64);
+
+ case lldb::eFormatVectorOfSInt16:
+ return ast_ctx->GetIntTypeFromBitSize(16, true);
+
+ case lldb::eFormatVectorOfSInt32:
+ return ast_ctx->GetIntTypeFromBitSize(32, true);
+
+ case lldb::eFormatVectorOfSInt64:
+ return ast_ctx->GetIntTypeFromBitSize(64, true);
+
+ case lldb::eFormatVectorOfSInt8:
+ return ast_ctx->GetIntTypeFromBitSize(8, true);
+
+ case lldb::eFormatVectorOfUInt128:
+ return ast_ctx->GetIntTypeFromBitSize(128, false);
+
+ case lldb::eFormatVectorOfUInt16:
+ return ast_ctx->GetIntTypeFromBitSize(16, false);
+
+ case lldb::eFormatVectorOfUInt32:
+ return ast_ctx->GetIntTypeFromBitSize(32, false);
+
+ case lldb::eFormatVectorOfUInt64:
+ return ast_ctx->GetIntTypeFromBitSize(64, false);
+
+ case lldb::eFormatVectorOfUInt8:
+ return ast_ctx->GetIntTypeFromBitSize(8, false);
+
+ case lldb::eFormatDefault:
+ return element_type;
+
+ case lldb::eFormatBinary:
+ case lldb::eFormatComplexInteger:
+ case lldb::eFormatDecimal:
+ case lldb::eFormatEnum:
+ case lldb::eFormatInstruction:
+ case lldb::eFormatOSType:
+ case lldb::eFormatVoid:
+ default:
+ return ast_ctx->GetIntTypeFromBitSize(8, false);
+ }
+}
+
+static lldb::Format
+GetItemFormatForFormat (lldb::Format format,
+ ClangASTType element_type)
+{
+ switch (format)
+ {
+ case lldb::eFormatVectorOfChar:
+ return lldb::eFormatChar;
+
+ case lldb::eFormatVectorOfFloat32:
+ case lldb::eFormatVectorOfFloat64:
+ return lldb::eFormatFloat;
+
+ case lldb::eFormatVectorOfSInt16:
+ case lldb::eFormatVectorOfSInt32:
+ case lldb::eFormatVectorOfSInt64:
+ case lldb::eFormatVectorOfSInt8:
+ return lldb::eFormatDecimal;
+
+ case lldb::eFormatVectorOfUInt128:
+ case lldb::eFormatVectorOfUInt16:
+ case lldb::eFormatVectorOfUInt32:
+ case lldb::eFormatVectorOfUInt64:
+ case lldb::eFormatVectorOfUInt8:
+ return lldb::eFormatUnsigned;
+
+ case lldb::eFormatBinary:
+ case lldb::eFormatComplexInteger:
+ case lldb::eFormatDecimal:
+ case lldb::eFormatEnum:
+ case lldb::eFormatInstruction:
+ case lldb::eFormatOSType:
+ case lldb::eFormatVoid:
+ return eFormatHex;
+
+ case lldb::eFormatDefault:
+ {
+ // special case the (default, char) combination to actually display as an integer value
+ // most often, you won't want to see the ASCII characters... (and if you do, eFormatChar is a keystroke away)
+ bool is_char = element_type.IsCharType();
+ bool is_signed = false;
+ element_type.IsIntegerType(is_signed);
+ return is_char ? (is_signed ? lldb::eFormatDecimal : eFormatHex) : format;
+ }
+ break;
+
+ default:
+ return format;
+ }
+}
+
+static size_t
+CalculateNumChildren (ClangASTType container_type,
+ ClangASTType element_type,
+ lldb_private::ExecutionContextScope *exe_scope = nullptr // does not matter here because all we trade in are basic types
+ )
+{
+ auto container_size = container_type.GetByteSize(exe_scope);
+ auto element_size = element_type.GetByteSize(exe_scope);
+
+ if (element_size)
+ {
+ if (container_size % element_size)
+ return 0;
+ return container_size / element_size;
+ }
+ return 0;
+}
+
+namespace lldb_private {
+ namespace formatters {
+
+ class VectorTypeSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ VectorTypeSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+ SyntheticChildrenFrontEnd(*valobj_sp),
+ m_parent_format (eFormatInvalid),
+ m_item_format(eFormatInvalid),
+ m_child_type(),
+ m_num_children(0)
+ {}
+
+ virtual size_t
+ CalculateNumChildren ()
+ {
+ return m_num_children;
+ }
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx)
+ {
+ if (idx >= CalculateNumChildren())
+ return lldb::ValueObjectSP();
+ auto offset = idx * m_child_type.GetByteSize(nullptr);
+ ValueObjectSP child_sp(m_backend.GetSyntheticChildAtOffset(offset, m_child_type, true));
+ if (!child_sp)
+ return child_sp;
+
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ child_sp->SetName( ConstString( idx_name.GetData() ) );
+
+ child_sp->SetFormat(m_item_format);
+
+ return child_sp;
+ }
+
+ virtual bool
+ Update()
+ {
+ m_parent_format = m_backend.GetFormat();
+ ClangASTType parent_type(m_backend.GetClangType());
+ ClangASTType element_type;
+ parent_type.IsVectorType(&element_type, nullptr);
+ m_child_type = ::GetClangTypeForFormat(m_parent_format, element_type, ClangASTContext::GetASTContext(parent_type.GetASTContext()));
+ m_num_children = ::CalculateNumChildren(parent_type,
+ m_child_type);
+ m_item_format = GetItemFormatForFormat(m_parent_format,
+ m_child_type);
+ return false;
+ }
+
+ virtual bool
+ MightHaveChildren ()
+ {
+ return true;
+ }
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name)
+ {
+ const char* item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+ return UINT32_MAX;
+ return idx;
+ }
+
+ virtual
+ ~VectorTypeSyntheticFrontEnd () {}
+
+ private:
+ lldb::Format m_parent_format;
+ lldb::Format m_item_format;
+ ClangASTType m_child_type;
+ size_t m_num_children;
+ };
+ }
+}
+
+lldb_private::SyntheticChildrenFrontEnd*
+lldb_private::formatters::VectorTypeSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ if (!valobj_sp)
+ return NULL;
+ return (new VectorTypeSyntheticFrontEnd(valobj_sp));
+}
diff --git a/source/Expression/ClangASTSource.cpp b/source/Expression/ClangASTSource.cpp
index 9a6d6e532255..3988cd674afd 100644
--- a/source/Expression/ClangASTSource.cpp
+++ b/source/Expression/ClangASTSource.cpp
@@ -16,15 +16,45 @@
#include "lldb/Expression/ASTDumper.h"
#include "lldb/Expression/ClangASTSource.h"
#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangModulesDeclVendor.h"
+#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangNamespaceDecl.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/TaggedASTType.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
+#include <vector>
+
using namespace clang;
using namespace lldb_private;
+//------------------------------------------------------------------
+// Scoped class that will remove an active lexical decl from the set
+// when it goes out of scope.
+//------------------------------------------------------------------
+namespace {
+ class ScopedLexicalDeclEraser
+ {
+ public:
+ ScopedLexicalDeclEraser(std::set<const clang::Decl *> &decls,
+ const clang::Decl *decl)
+ : m_active_lexical_decls(decls), m_decl(decl)
+ {
+ }
+
+ ~ScopedLexicalDeclEraser()
+ {
+ m_active_lexical_decls.erase(m_decl);
+ }
+
+ private:
+ std::set<const clang::Decl *> &m_active_lexical_decls;
+ const clang::Decl *m_decl;
+ };
+}
+
ClangASTSource::~ClangASTSource()
{
m_ast_importer->ForgetDestination(m_ast_context);
@@ -186,6 +216,12 @@ ClangASTSource::CompleteType (TagDecl *tag_decl)
dumper.ToLog(log, " [CTD] ");
}
+ auto iter = m_active_lexical_decls.find(tag_decl);
+ if (iter != m_active_lexical_decls.end())
+ return;
+ m_active_lexical_decls.insert(tag_decl);
+ ScopedLexicalDeclEraser eraser(m_active_lexical_decls, tag_decl);
+
if (!m_ast_importer->CompleteTagDecl (tag_decl))
{
// We couldn't complete the type. Maybe there's a definition
@@ -397,6 +433,12 @@ ClangASTSource::FindExternalLexicalDecls (const DeclContext *decl_context,
if (!context_decl)
return ELR_Failure;
+ auto iter = m_active_lexical_decls.find(context_decl);
+ if (iter != m_active_lexical_decls.end())
+ return ELR_Failure;
+ m_active_lexical_decls.insert(context_decl);
+ ScopedLexicalDeclEraser eraser(m_active_lexical_decls, context_decl);
+
static unsigned int invocation_id = 0;
unsigned int current_id = invocation_id++;
@@ -1529,41 +1571,50 @@ ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context)
while(0);
}
-typedef llvm::DenseMap <const FieldDecl *, uint64_t> FieldOffsetMap;
-typedef llvm::DenseMap <const CXXRecordDecl *, CharUnits> BaseOffsetMap;
+typedef llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsetMap;
+typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetMap;
template <class D, class O>
static bool
-ImportOffsetMap (llvm::DenseMap <const D*, O> &destination_map,
- llvm::DenseMap <const D*, O> &source_map,
- ClangASTImporter *importer,
- ASTContext &dest_ctx)
+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)
+ // When importing fields into a new record, clang has a hard requirement that
+ // fields be imported in field offset order. Since they are stored in a DenseMap
+ // with a pointer as the key type, this means we cannot simply iterate over the
+ // map, as the order will be non-deterministic. Instead we have to sort by the offset
+ // and then insert in sorted order.
+ typedef llvm::DenseMap<const D *, O> MapType;
+ typedef typename MapType::value_type PairType;
+ std::vector<PairType> sorted_items;
+ sorted_items.reserve(source_map.size());
+ sorted_items.assign(source_map.begin(), source_map.end());
+ std::sort(sorted_items.begin(), sorted_items.end(),
+ [](const PairType &lhs, const PairType &rhs)
+ {
+ return lhs.second < rhs.second;
+ });
+
+ for (const auto &item : sorted_items)
{
- DeclFromUser <D> user_decl(const_cast<D*>(fi->first));
+ DeclFromUser<D> user_decl(const_cast<D *>(item.first));
DeclFromParser <D> parser_decl(user_decl.Import(importer, dest_ctx));
if (parser_decl.IsInvalid())
return false;
- destination_map.insert(std::pair<const D *, O>(parser_decl.decl, fi->second));
+ destination_map.insert(std::pair<const D *, O>(parser_decl.decl, item.second));
}
return true;
}
-template <bool IsVirtual> bool ExtractBaseOffsets (const ASTRecordLayout &record_layout,
- DeclFromUser<const CXXRecordDecl> &record,
- BaseOffsetMap &base_offsets)
+template <bool IsVirtual>
+bool
+ExtractBaseOffsets(const ASTRecordLayout &record_layout, DeclFromUser<const CXXRecordDecl> &record,
+ BaseOffsetMap &base_offsets)
{
- 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)
+ 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;
@@ -1598,11 +1649,8 @@ template <bool IsVirtual> bool ExtractBaseOffsets (const ASTRecordLayout &record
}
bool
-ClangASTSource::layoutRecordType(const RecordDecl *record,
- uint64_t &size,
- uint64_t &alignment,
- FieldOffsetMap &field_offsets,
- BaseOffsetMap &base_offsets,
+ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, uint64_t &alignment,
+ FieldOffsetMap &field_offsets, BaseOffsetMap &base_offsets,
BaseOffsetMap &virtual_base_offsets)
{
ClangASTMetrics::RegisterRecordLayout();
@@ -1637,9 +1685,7 @@ ClangASTSource::layoutRecordType(const RecordDecl *record,
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)
+ 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.
@@ -1682,9 +1728,8 @@ ClangASTSource::layoutRecordType(const RecordDecl *record,
fi != fe;
++fi)
{
- log->Printf("LRT[%u] (FieldDecl*)%p, Name = '%s', Offset = %" PRId64 " bits",
- current_id, static_cast<void*>(*fi),
- fi->getNameAsString().c_str(), field_offsets[*fi]);
+ log->Printf("LRT[%u] (FieldDecl*)%p, Name = '%s', Offset = %" PRId64 " bits", 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())
@@ -1701,13 +1746,11 @@ ClangASTSource::layoutRecordType(const RecordDecl *record,
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 " : ""),
- static_cast<void*>(base_cxx_record.decl),
+ log->Printf("LRT[%u] %s(CXXRecordDecl*)%p, Name = '%s', Offset = %" PRId64 " chars", 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
@@ -1883,7 +1926,7 @@ NameSearchContext::AddVarDecl(const ClangASTType &type)
}
clang::NamedDecl *
-NameSearchContext::AddFunDecl (const ClangASTType &type)
+NameSearchContext::AddFunDecl (const ClangASTType &type, bool extern_c)
{
assert (type && "Type for variable must be valid!");
@@ -1902,15 +1945,26 @@ NameSearchContext::AddFunDecl (const ClangASTType &type)
const bool isInlineSpecified = false;
const bool hasWrittenPrototype = true;
const bool isConstexprSpecified = false;
+
+ clang::DeclContext *context = const_cast<DeclContext*>(m_decl_context);
+
+ if (extern_c) {
+ context = LinkageSpecDecl::Create(*ast,
+ context,
+ SourceLocation(),
+ SourceLocation(),
+ clang::LinkageSpecDecl::LanguageIDs::lang_c,
+ false);
+ }
clang::FunctionDecl *func_decl = FunctionDecl::Create (*ast,
- const_cast<DeclContext*>(m_decl_context),
+ context,
SourceLocation(),
SourceLocation(),
m_decl_name.getAsIdentifierInfo(),
qual_type,
NULL,
- SC_Static,
+ SC_Extern,
isInlineSpecified,
hasWrittenPrototype,
isConstexprSpecified);
@@ -1933,7 +1987,7 @@ NameSearchContext::AddFunDecl (const ClangASTType &type)
QualType arg_qual_type (func_proto_type->getParamType(ArgIndex));
parm_var_decls.push_back(ParmVarDecl::Create (*ast,
- const_cast<DeclContext*>(m_decl_context),
+ const_cast<DeclContext*>(context),
SourceLocation(),
SourceLocation(),
NULL,
@@ -1969,7 +2023,7 @@ NameSearchContext::AddGenericFunDecl()
ArrayRef<QualType>(), // argument types
proto_info));
- return AddFunDecl(ClangASTType (m_ast_source.m_ast_context, generic_function_type));
+ return AddFunDecl(ClangASTType (m_ast_source.m_ast_context, generic_function_type), true);
}
clang::NamedDecl *
@@ -2008,7 +2062,7 @@ NameSearchContext::AddTypeDecl(const ClangASTType &clang_type)
}
void
-NameSearchContext::AddLookupResult (clang::DeclContextLookupConstResult result)
+NameSearchContext::AddLookupResult (clang::DeclContextLookupResult result)
{
for (clang::NamedDecl *decl : result)
m_decls.push_back (decl);
diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp
index e3027378422f..1013bb540601 100644
--- a/source/Expression/ClangExpressionDeclMap.cpp
+++ b/source/Expression/ClangExpressionDeclMap.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Decl.h"
@@ -22,6 +23,7 @@
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Expression/ASTDumper.h"
#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangModulesDeclVendor.h"
#include "lldb/Expression/ClangPersistentVariables.h"
#include "lldb/Expression/Materializer.h"
#include "lldb/Host/Endian.h"
@@ -110,6 +112,13 @@ ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx,
}
void
+ClangExpressionDeclMap::InstallCodeGenerator (clang::ASTConsumer *code_gen)
+{
+ assert(m_parser_vars);
+ m_parser_vars->m_code_gen = code_gen;
+}
+
+void
ClangExpressionDeclMap::DidParse()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@@ -492,33 +501,56 @@ FindCodeSymbolInContext
SymbolContextList &sc_list
)
{
+ sc_list.Clear();
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);
+ sym_ctx.module_sp->FindFunctions(name,
+ NULL,
+ eFunctionNameTypeAuto,
+ true, // include_symbols
+ false, // include_inlines
+ true, // append
+ temp_sc_list);
+ if (temp_sc_list.GetSize() == 0)
+ {
+ if (sym_ctx.target_sp)
+ sym_ctx.target_sp->GetImages().FindFunctions(name,
+ eFunctionNameTypeAuto,
+ true, // include_symbols
+ false, // include_inlines
+ true, // append
+ temp_sc_list);
+ }
+ SymbolContextList internal_symbol_sc_list;
unsigned temp_sc_list_size = temp_sc_list.GetSize();
for (unsigned i = 0; i < temp_sc_list_size; i++)
{
- SymbolContext sym_ctx;
- temp_sc_list.GetContextAtIndex(i, sym_ctx);
- if (sym_ctx.symbol)
+ SymbolContext sc;
+ temp_sc_list.GetContextAtIndex(i, sc);
+ if (sc.function)
{
- switch (sym_ctx.symbol->GetType())
+ sc_list.Append(sc);
+ }
+ else if (sc.symbol)
+ {
+ if (sc.symbol->IsExternal())
+ {
+ sc_list.Append(sc);
+ }
+ else
{
- case eSymbolTypeCode:
- case eSymbolTypeResolver:
- case eSymbolTypeReExported:
- sc_list.Append(sym_ctx);
- break;
-
- default:
- break;
+ internal_symbol_sc_list.Append(sc);
}
}
}
+
+ // If we had internal symbols and we didn't find any external symbols or
+ // functions in debug info, then fallback to the internal symbols
+ if (sc_list.GetSize() == 0 && internal_symbol_sc_list.GetSize())
+ {
+ sc_list = internal_symbol_sc_list;
+ }
}
bool
@@ -564,31 +596,15 @@ ClangExpressionDeclMap::GetFunctionAddress
sc_list_size = sc_list.GetSize();
}
}
-
- if (sc_list_size == 0)
- {
- // Sometimes we get a mangled name for a global function that actually should be "extern C."
- // This is a hack to compensate.
-
- const bool is_mangled = true;
- Mangled mangled(name, is_mangled);
-
- CPPLanguageRuntime::MethodName method_name(mangled.GetDemangledName());
-
- llvm::StringRef basename = method_name.GetBasename();
-
- if (!basename.empty())
- {
- FindCodeSymbolInContext(ConstString(basename), m_parser_vars->m_sym_ctx, sc_list);
- sc_list_size = sc_list.GetSize();
- }
- }
+
+ lldb::addr_t intern_callable_load_addr = LLDB_INVALID_ADDRESS;
for (uint32_t i=0; i<sc_list_size; ++i)
{
SymbolContext sym_ctx;
sc_list.GetContextAtIndex(i, sym_ctx);
+
lldb::addr_t callable_load_addr = LLDB_INVALID_ADDRESS;
if (sym_ctx.function)
@@ -601,7 +617,13 @@ ClangExpressionDeclMap::GetFunctionAddress
}
else if (sym_ctx.symbol)
{
- callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target);
+ if (sym_ctx.symbol->IsExternal())
+ callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target);
+ else
+ {
+ if (intern_callable_load_addr == LLDB_INVALID_ADDRESS)
+ intern_callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target);
+ }
}
if (callable_load_addr != LLDB_INVALID_ADDRESS)
@@ -610,6 +632,14 @@ ClangExpressionDeclMap::GetFunctionAddress
return true;
}
}
+
+ // See if we found an internal symbol
+ if (intern_callable_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ func_addr = intern_callable_load_addr;
+ return true;
+ }
+
return false;
}
@@ -635,74 +665,71 @@ ClangExpressionDeclMap::GetSymbolAddress (Target &target,
SymbolContext sym_ctx;
sc_list.GetContextAtIndex(i, sym_ctx);
- const Address *sym_address = &sym_ctx.symbol->GetAddress();
+ const Address sym_address = sym_ctx.symbol->GetAddress();
- if (!sym_address || !sym_address->IsValid())
+ if (!sym_address.IsValid())
continue;
- if (sym_address)
+ switch (sym_ctx.symbol->GetType())
{
- switch (sym_ctx.symbol->GetType())
- {
- case eSymbolTypeCode:
- case eSymbolTypeTrampoline:
- symbol_load_addr = sym_address->GetCallableLoadAddress (&target);
- break;
+ case eSymbolTypeCode:
+ case eSymbolTypeTrampoline:
+ symbol_load_addr = sym_address.GetCallableLoadAddress (&target);
+ break;
- case eSymbolTypeResolver:
- symbol_load_addr = sym_address->GetCallableLoadAddress (&target, true);
- break;
+ case eSymbolTypeResolver:
+ symbol_load_addr = sym_address.GetCallableLoadAddress (&target, true);
+ break;
- case eSymbolTypeReExported:
+ case eSymbolTypeReExported:
+ {
+ ConstString reexport_name = sym_ctx.symbol->GetReExportedSymbolName();
+ if (reexport_name)
{
- ConstString reexport_name = sym_ctx.symbol->GetReExportedSymbolName();
- if (reexport_name)
+ ModuleSP reexport_module_sp;
+ ModuleSpec reexport_module_spec;
+ reexport_module_spec.GetPlatformFileSpec() = sym_ctx.symbol->GetReExportedSymbolSharedLibrary();
+ if (reexport_module_spec.GetPlatformFileSpec())
{
- ModuleSP reexport_module_sp;
- ModuleSpec reexport_module_spec;
- reexport_module_spec.GetPlatformFileSpec() = sym_ctx.symbol->GetReExportedSymbolSharedLibrary();
- if (reexport_module_spec.GetPlatformFileSpec())
+ reexport_module_sp = target.GetImages().FindFirstModule(reexport_module_spec);
+ if (!reexport_module_sp)
{
+ reexport_module_spec.GetPlatformFileSpec().GetDirectory().Clear();
reexport_module_sp = target.GetImages().FindFirstModule(reexport_module_spec);
- if (!reexport_module_sp)
- {
- reexport_module_spec.GetPlatformFileSpec().GetDirectory().Clear();
- reexport_module_sp = target.GetImages().FindFirstModule(reexport_module_spec);
- }
}
- symbol_load_addr = GetSymbolAddress(target, process, sym_ctx.symbol->GetReExportedSymbolName(), symbol_type, reexport_module_sp.get());
}
+ symbol_load_addr = GetSymbolAddress(target, process, sym_ctx.symbol->GetReExportedSymbolName(), symbol_type, reexport_module_sp.get());
}
- break;
-
- case eSymbolTypeData:
- case eSymbolTypeRuntime:
- case eSymbolTypeVariable:
- case eSymbolTypeLocal:
- case eSymbolTypeParam:
- case eSymbolTypeInvalid:
- case eSymbolTypeAbsolute:
- case eSymbolTypeException:
- case eSymbolTypeSourceFile:
- case eSymbolTypeHeaderFile:
- case eSymbolTypeObjectFile:
- case eSymbolTypeCommonBlock:
- case eSymbolTypeBlock:
- case eSymbolTypeVariableType:
- case eSymbolTypeLineEntry:
- case eSymbolTypeLineHeader:
- case eSymbolTypeScopeBegin:
- case eSymbolTypeScopeEnd:
- case eSymbolTypeAdditional:
- case eSymbolTypeCompiler:
- case eSymbolTypeInstrumentation:
- case eSymbolTypeUndefined:
- case eSymbolTypeObjCClass:
- case eSymbolTypeObjCMetaClass:
- case eSymbolTypeObjCIVar:
- symbol_load_addr = sym_address->GetLoadAddress (&target);
- break;
- }
+ }
+ break;
+
+ case eSymbolTypeData:
+ case eSymbolTypeRuntime:
+ case eSymbolTypeVariable:
+ case eSymbolTypeLocal:
+ case eSymbolTypeParam:
+ case eSymbolTypeInvalid:
+ case eSymbolTypeAbsolute:
+ case eSymbolTypeException:
+ case eSymbolTypeSourceFile:
+ case eSymbolTypeHeaderFile:
+ case eSymbolTypeObjectFile:
+ case eSymbolTypeCommonBlock:
+ case eSymbolTypeBlock:
+ case eSymbolTypeVariableType:
+ case eSymbolTypeLineEntry:
+ case eSymbolTypeLineHeader:
+ case eSymbolTypeScopeBegin:
+ case eSymbolTypeScopeEnd:
+ case eSymbolTypeAdditional:
+ case eSymbolTypeCompiler:
+ case eSymbolTypeInstrumentation:
+ case eSymbolTypeUndefined:
+ case eSymbolTypeObjCClass:
+ case eSymbolTypeObjCMetaClass:
+ case eSymbolTypeObjCIVar:
+ symbol_load_addr = sym_address.GetLoadAddress (&target);
+ break;
}
}
@@ -750,9 +777,9 @@ ClangExpressionDeclMap::FindGlobalDataSymbol (Target &target,
if (sym_ctx.symbol)
{
const Symbol *symbol = sym_ctx.symbol;
- const Address *sym_address = &symbol->GetAddress();
+ const Address sym_address = symbol->GetAddress();
- if (sym_address && sym_address->IsValid())
+ if (sym_address.IsValid())
{
switch (symbol->GetType())
{
@@ -789,6 +816,11 @@ ClangExpressionDeclMap::FindGlobalDataSymbol (Target &target,
reexport_module_sp = target.GetImages().FindFirstModule(reexport_module_spec);
}
}
+ // Don't allow us to try and resolve a re-exported symbol if it is the same
+ // as the current symbol
+ if (name == symbol->GetReExportedSymbolName() && module == reexport_module_sp.get())
+ return NULL;
+
return FindGlobalDataSymbol(target, symbol->GetReExportedSymbolName(), reexport_module_sp.get());
}
}
@@ -1053,7 +1085,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
{
// This branch will get hit if we are executing code in the context of a function that
// 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 "this" variable in the the current
+ // method of the class. In that case, just look up the "this" variable in the current
// 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.
@@ -1172,7 +1204,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
{
// This branch will get hit if we are executing code in the context of a function that
// 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
+ // method of the class. In that case, just look up the "self" variable in the current
// scope and use its type.
VariableList *vars = frame->GetVariableList(false);
@@ -1442,6 +1474,62 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
}
}
}
+
+ if (!context.m_found.function_with_type_info)
+ {
+ // Try the modules next.
+
+ do
+ {
+ if (ClangModulesDeclVendor *modules_decl_vendor = m_target->GetClangModulesDeclVendor())
+ {
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <clang::NamedDecl *> decls;
+
+ if (!modules_decl_vendor->FindDecls(name,
+ append,
+ max_matches,
+ decls))
+ break;
+
+ clang::NamedDecl *const decl_from_modules = decls[0];
+
+ if (llvm::isa<clang::FunctionDecl>(decl_from_modules))
+ {
+ if (log)
+ {
+ log->Printf(" CAS::FEVD[%u] Matching function found for \"%s\" in the modules",
+ current_id,
+ name.GetCString());
+ }
+
+ clang::Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, &decl_from_modules->getASTContext(), decl_from_modules);
+ clang::FunctionDecl *copied_function_decl = copied_decl ? dyn_cast<clang::FunctionDecl>(copied_decl) : nullptr;
+
+ if (!copied_function_decl)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a function declaration from the modules",
+ current_id);
+
+ break;
+ }
+
+ if (copied_function_decl->getBody() && m_parser_vars->m_code_gen)
+ {
+ DeclGroupRef decl_group_ref(copied_function_decl);
+ m_parser_vars->m_code_gen->HandleTopLevelDecl(decl_group_ref);
+ }
+
+ context.AddNamedDecl(copied_function_decl);
+
+ context.m_found.function_with_type_info = true;
+ context.m_found.function = true;
+ }
+ }
+ } while (0);
+ }
if (target && !context.m_found.variable && !namespace_decl)
{
@@ -1727,7 +1815,7 @@ ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context,
entity->EnableParserVars(GetParserID());
ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID());
- const Address &symbol_address = symbol.GetAddress();
+ 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());
@@ -1866,7 +1954,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
NamedDecl *function_decl = NULL;
- const Address *fun_address = NULL;
+ Address fun_address;
ClangASTType function_clang_type;
bool is_indirect_function = false;
@@ -1891,7 +1979,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
return;
}
- fun_address = &function->GetAddressRange().GetBaseAddress();
+ fun_address = function->GetAddressRange().GetBaseAddress();
ClangASTType copied_function_type = GuardedCopyType(function_clang_type);
if (copied_function_type)
@@ -1925,7 +2013,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
}
else if (symbol)
{
- fun_address = &symbol->GetAddress();
+ fun_address = symbol->GetAddress();
function_decl = context.AddGenericFunDecl();
is_indirect_function = symbol->IsIndirect();
}
@@ -1938,7 +2026,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
- lldb::addr_t load_addr = fun_address->GetCallableLoadAddress(target, is_indirect_function);
+ 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,
@@ -1961,7 +2049,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
{
// We have to try finding a file address.
- lldb::addr_t file_addr = fun_address->GetFileAddress();
+ lldb::addr_t file_addr = fun_address.GetFileAddress();
parser_vars->m_lldb_value.SetValueType(Value::eValueTypeFileAddress);
parser_vars->m_lldb_value.GetScalar() = file_addr;
@@ -1977,7 +2065,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
StreamString ss;
- fun_address->Dump(&ss, m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(), Address::DumpStyleResolvedDescription);
+ 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,
diff --git a/source/Expression/ClangExpressionParser.cpp b/source/Expression/ClangExpressionParser.cpp
index d05d9b99df07..3d5350d34028 100644
--- a/source/Expression/ClangExpressionParser.cpp
+++ b/source/Expression/ClangExpressionParser.cpp
@@ -7,14 +7,13 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Expression/ClangExpressionParser.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
@@ -23,6 +22,7 @@
#include "lldb/Expression/ClangExpression.h"
#include "lldb/Expression/ClangExpressionDeclMap.h"
#include "lldb/Expression/ClangModulesDeclVendor.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Expression/IRInterpreter.h"
@@ -95,12 +95,15 @@ std::string GetBuiltinIncludePath(const char *Argv0) {
class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks
{
- ClangModulesDeclVendor &m_decl_vendor;
- StreamString m_error_stream;
- bool m_has_errors = false;
+ ClangModulesDeclVendor &m_decl_vendor;
+ ClangPersistentVariables &m_persistent_vars;
+ StreamString m_error_stream;
+ bool m_has_errors = false;
public:
- LLDBPreprocessorCallbacks(ClangModulesDeclVendor &decl_vendor) :
- m_decl_vendor(decl_vendor)
+ LLDBPreprocessorCallbacks(ClangModulesDeclVendor &decl_vendor,
+ ClangPersistentVariables &persistent_vars) :
+ m_decl_vendor(decl_vendor),
+ m_persistent_vars(persistent_vars)
{
}
@@ -108,19 +111,26 @@ public:
ModuleIdPath path,
const clang::Module * /*null*/)
{
- std::vector<llvm::StringRef> string_path;
+ std::vector<ConstString> string_path;
for (const std::pair<IdentifierInfo *, SourceLocation> &component : path)
{
- string_path.push_back(component.first->getName());
+ string_path.push_back(ConstString(component.first->getName()));
}
StreamString error_stream;
- if (!m_decl_vendor.AddModule(string_path, m_error_stream))
+ ClangModulesDeclVendor::ModuleVector exported_modules;
+
+ if (!m_decl_vendor.AddModule(string_path, &exported_modules, m_error_stream))
{
m_has_errors = true;
}
+
+ for (ClangModulesDeclVendor::ModuleID module : exported_modules)
+ {
+ m_persistent_vars.AddHandLoadedClangModule(module);
+ }
}
bool hasErrors()
@@ -227,6 +237,9 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
if (expr.DesiredResultType() == ClangExpression::eResultTypeId)
m_compiler->getLangOpts().DebuggerCastResultToId = true;
+ m_compiler->getLangOpts().CharIsSigned =
+ ArchSpec(m_compiler->getTargetOpts().Triple.c_str()).CharIsSignedByDefault();
+
// 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
@@ -294,7 +307,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
if (ClangModulesDeclVendor *decl_vendor = target_sp->GetClangModulesDeclVendor())
{
- std::unique_ptr<PPCallbacks> pp_callbacks(new LLDBPreprocessorCallbacks(*decl_vendor));
+ std::unique_ptr<PPCallbacks> pp_callbacks(new LLDBPreprocessorCallbacks(*decl_vendor, target_sp->GetPersistentVariables()));
m_pp_callbacks = static_cast<LLDBPreprocessorCallbacks*>(pp_callbacks.get());
m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks));
}
@@ -305,10 +318,10 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
m_builtin_context.reset(new Builtin::Context());
std::unique_ptr<clang::ASTContext> ast_context(new ASTContext(m_compiler->getLangOpts(),
- m_compiler->getSourceManager(),
- m_compiler->getPreprocessor().getIdentifierTable(),
- *m_selector_table.get(),
- *m_builtin_context.get()));
+ m_compiler->getSourceManager(),
+ m_compiler->getPreprocessor().getIdentifierTable(),
+ *m_selector_table.get(),
+ *m_builtin_context.get()));
ast_context->InitBuiltinTypes(m_compiler->getTarget());
@@ -328,6 +341,8 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
m_llvm_context.reset(new LLVMContext());
m_code_generator.reset(CreateLLVMCodeGen(m_compiler->getDiagnostics(),
module_name,
+ m_compiler->getHeaderSearchOpts(),
+ m_compiler->getPreprocessorOpts(),
m_compiler->getCodeGenOpts(),
*m_llvm_context));
}
@@ -394,6 +409,9 @@ ClangExpressionParser::Parse (Stream &stream)
ASTConsumer *ast_transformer = m_expr.ASTTransformer(m_code_generator.get());
+ if (ClangExpressionDeclMap *decl_map = m_expr.DeclMap())
+ decl_map->InstallCodeGenerator(m_code_generator.get());
+
if (ast_transformer)
ParseAST(m_compiler->getPreprocessor(), ast_transformer, m_compiler->getASTContext());
else
diff --git a/source/Expression/ClangModulesDeclVendor.cpp b/source/Expression/ClangModulesDeclVendor.cpp
index 0800b52e7e99..97a4d088b982 100644
--- a/source/Expression/ClangModulesDeclVendor.cpp
+++ b/source/Expression/ClangModulesDeclVendor.cpp
@@ -11,10 +11,12 @@
#include "lldb/Expression/ClangModulesDeclVendor.h"
+#include "lldb/Core/Log.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/Target.h"
#include "clang/Basic/TargetInfo.h"
@@ -60,25 +62,52 @@ namespace {
std::unique_ptr<clang::Parser> &&parser);
virtual bool
- AddModule(std::vector<llvm::StringRef> &path,
- Stream &error_stream);
+ AddModule(ModulePath &path,
+ ModuleVector *exported_modules,
+ Stream &error_stream) override;
+
+ virtual bool
+ AddModulesForCompileUnit(CompileUnit &cu,
+ ModuleVector &exported_modules,
+ Stream &error_stream) override;
virtual uint32_t
FindDecls (const ConstString &name,
bool append,
uint32_t max_matches,
- std::vector <clang::NamedDecl*> &decls);
+ std::vector <clang::NamedDecl*> &decls) override;
+
+ virtual void
+ ForEachMacro(const ModuleVector &modules,
+ std::function<bool (const std::string &)> handler) override;
~ClangModulesDeclVendorImpl();
private:
+ void
+ ReportModuleExportsHelper (std::set<ClangModulesDeclVendor::ModuleID> &exports,
+ clang::Module *module);
+
+ void
+ ReportModuleExports (ModuleVector &exports,
+ clang::Module *module);
+
clang::ModuleLoadResult
DoGetModule(clang::ModuleIdPath path, bool make_visible);
+ bool m_enabled = false;
+
llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> m_diagnostics_engine;
llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> m_compiler_invocation;
std::unique_ptr<clang::CompilerInstance> m_compiler_instance;
std::unique_ptr<clang::Parser> m_parser;
+ size_t m_source_location_index = 0; // used to give name components fake SourceLocations
+
+ typedef std::vector<ConstString> ImportedModule;
+ typedef std::map<ImportedModule, clang::Module *> ImportedModuleMap;
+ typedef std::set<ModuleID> ImportedModuleSet;
+ ImportedModuleMap m_imported_modules;
+ ImportedModuleSet m_user_imported_modules;
};
}
@@ -151,12 +180,47 @@ ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl(llvm::IntrusiveRefCntPtr<
m_diagnostics_engine(diagnostics_engine),
m_compiler_invocation(compiler_invocation),
m_compiler_instance(std::move(compiler_instance)),
- m_parser(std::move(parser))
+ m_parser(std::move(parser)),
+ m_imported_modules()
{
}
+void
+ClangModulesDeclVendorImpl::ReportModuleExportsHelper (std::set<ClangModulesDeclVendor::ModuleID> &exports,
+ clang::Module *module)
+{
+ if (exports.count(reinterpret_cast<ClangModulesDeclVendor::ModuleID>(module)))
+ return;
+
+ exports.insert(reinterpret_cast<ClangModulesDeclVendor::ModuleID>(module));
+
+ llvm::SmallVector<clang::Module*, 2> sub_exports;
+
+ module->getExportedModules(sub_exports);
+
+ for (clang::Module *module : sub_exports)
+ {
+ ReportModuleExportsHelper(exports, module);
+ }
+}
+
+void
+ClangModulesDeclVendorImpl::ReportModuleExports (ClangModulesDeclVendor::ModuleVector &exports,
+ clang::Module *module)
+{
+ std::set<ClangModulesDeclVendor::ModuleID> exports_set;
+
+ ReportModuleExportsHelper(exports_set, module);
+
+ for (ModuleID module : exports_set)
+ {
+ exports.push_back(module);
+ }
+}
+
bool
-ClangModulesDeclVendorImpl::AddModule(std::vector<llvm::StringRef> &path,
+ClangModulesDeclVendorImpl::AddModule(ModulePath &path,
+ ModuleVector *exported_modules,
Stream &error_stream)
{
// Fail early.
@@ -167,22 +231,43 @@ ClangModulesDeclVendorImpl::AddModule(std::vector<llvm::StringRef> &path,
return false;
}
- if (!m_compiler_instance->getPreprocessor().getHeaderSearchInfo().lookupModule(path[0]))
+ // Check if we've already imported this module.
+
+ std::vector<ConstString> imported_module;
+
+ for (ConstString path_component : path)
{
- error_stream.Printf("error: Header search couldn't locate module %s\n", path[0].str().c_str());
+ imported_module.push_back(path_component);
+ }
+
+ {
+ ImportedModuleMap::iterator mi = m_imported_modules.find(imported_module);
+
+ if (mi != m_imported_modules.end())
+ {
+ if (exported_modules)
+ {
+ ReportModuleExports(*exported_modules, mi->second);
+ }
+ return true;
+ }
+ }
+
+ if (!m_compiler_instance->getPreprocessor().getHeaderSearchInfo().lookupModule(path[0].GetStringRef()))
+ {
+ error_stream.Printf("error: Header search couldn't locate module %s\n", path[0].AsCString());
return false;
}
llvm::SmallVector<std::pair<clang::IdentifierInfo *, clang::SourceLocation>, 4> clang_path;
{
- size_t source_loc_counter = 0;
clang::SourceManager &source_manager = m_compiler_instance->getASTContext().getSourceManager();
- for (llvm::StringRef &component : path)
+ for (ConstString path_component : path)
{
- clang_path.push_back(std::make_pair(&m_compiler_instance->getASTContext().Idents.get(component),
- source_manager.getLocForStartOfFile(source_manager.getMainFileID()).getLocWithOffset(source_loc_counter++)));
+ clang_path.push_back(std::make_pair(&m_compiler_instance->getASTContext().Idents.get(path_component.GetStringRef()),
+ source_manager.getLocForStartOfFile(source_manager.getMainFileID()).getLocWithOffset(m_source_location_index++)));
}
}
@@ -195,7 +280,7 @@ ClangModulesDeclVendorImpl::AddModule(std::vector<llvm::StringRef> &path,
if (!top_level_module)
{
diagnostic_consumer->DumpDiagnostics(error_stream);
- error_stream.Printf("error: Couldn't load top-level module %s\n", path[0].str().c_str());
+ error_stream.Printf("error: Couldn't load top-level module %s\n", path[0].AsCString());
return false;
}
@@ -203,7 +288,7 @@ ClangModulesDeclVendorImpl::AddModule(std::vector<llvm::StringRef> &path,
for (size_t ci = 1; ci < path.size(); ++ci)
{
- llvm::StringRef &component = path[ci];
+ llvm::StringRef component = path[ci].GetStringRef();
submodule = submodule->findSubmodule(component.str());
if (!submodule)
{
@@ -215,7 +300,66 @@ ClangModulesDeclVendorImpl::AddModule(std::vector<llvm::StringRef> &path,
clang::Module *requested_module = DoGetModule(clang_path, true);
- return (requested_module != nullptr);
+ if (requested_module != nullptr)
+ {
+ if (exported_modules)
+ {
+ ReportModuleExports(*exported_modules, requested_module);
+ }
+
+ m_imported_modules[imported_module] = requested_module;
+
+ m_enabled = true;
+
+ return true;
+ }
+
+ return false;
+}
+
+
+bool
+ClangModulesDeclVendor::LanguageSupportsClangModules (lldb::LanguageType language)
+{
+ switch (language)
+ {
+ default:
+ return false;
+ // C++ and friends to be added
+ case lldb::LanguageType::eLanguageTypeC:
+ case lldb::LanguageType::eLanguageTypeC11:
+ case lldb::LanguageType::eLanguageTypeC89:
+ case lldb::LanguageType::eLanguageTypeC99:
+ case lldb::LanguageType::eLanguageTypeObjC:
+ return true;
+ }
+}
+
+bool
+ClangModulesDeclVendorImpl::AddModulesForCompileUnit(CompileUnit &cu,
+ ClangModulesDeclVendor::ModuleVector &exported_modules,
+ Stream &error_stream)
+{
+ if (LanguageSupportsClangModules(cu.GetLanguage()))
+ {
+ std::vector<ConstString> imported_modules = cu.GetImportedModules();
+
+ for (ConstString imported_module : imported_modules)
+ {
+ std::vector<ConstString> path;
+
+ path.push_back(imported_module);
+
+ if (!AddModule(path, &exported_modules, error_stream))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return true;
}
// ClangImporter::lookupValue
@@ -226,6 +370,11 @@ ClangModulesDeclVendorImpl::FindDecls (const ConstString &name,
uint32_t max_matches,
std::vector <clang::NamedDecl*> &decls)
{
+ if (!m_enabled)
+ {
+ return 0;
+ }
+
if (!append)
decls.clear();
@@ -252,6 +401,215 @@ ClangModulesDeclVendorImpl::FindDecls (const ConstString &name,
return num_matches;
}
+void
+ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVector &modules,
+ std::function<bool (const std::string &)> handler)
+{
+ if (!m_enabled)
+ {
+ return;
+ }
+
+ typedef std::map<ModuleID, ssize_t> ModulePriorityMap;
+ ModulePriorityMap module_priorities;
+
+ ssize_t priority = 0;
+
+ for (ModuleID module : modules)
+ {
+ module_priorities[module] = priority++;
+ }
+
+ if (m_compiler_instance->getPreprocessor().getExternalSource())
+ {
+ m_compiler_instance->getPreprocessor().getExternalSource()->ReadDefinedMacros();
+ }
+
+ for (clang::Preprocessor::macro_iterator mi = m_compiler_instance->getPreprocessor().macro_begin(),
+ me = m_compiler_instance->getPreprocessor().macro_end();
+ mi != me;
+ ++mi)
+ {
+ const clang::IdentifierInfo *ii = nullptr;
+
+ {
+ if (clang::IdentifierInfoLookup *lookup = m_compiler_instance->getPreprocessor().getIdentifierTable().getExternalIdentifierLookup())
+ {
+ lookup->get(mi->first->getName());
+ }
+ if (!ii)
+ {
+ ii = mi->first;
+ }
+ }
+
+ ssize_t found_priority = -1;
+ clang::MacroInfo *info = nullptr;
+
+ for (clang::ModuleMacro *macro : m_compiler_instance->getPreprocessor().getLeafModuleMacros(ii))
+ {
+ clang::Module *module = macro->getOwningModule();
+
+ {
+ ModulePriorityMap::iterator pi = module_priorities.find(reinterpret_cast<ModuleID>(module));
+
+ if (pi != module_priorities.end() && pi->second > found_priority)
+ {
+ info = macro->getMacroInfo();
+ found_priority = pi->second;
+ }
+ }
+
+ clang::Module *top_level_module = module->getTopLevelModule();
+
+ if (top_level_module != module)
+ {
+ ModulePriorityMap::iterator pi = module_priorities.find(reinterpret_cast<ModuleID>(top_level_module));
+
+ if ((pi != module_priorities.end()) && pi->second > found_priority)
+ {
+ info = macro->getMacroInfo();
+ found_priority = pi->second;
+ }
+ }
+ }
+
+ if (!info)
+ {
+ continue;
+ }
+
+ if (mi->second.getLatest()->getKind() == clang::MacroDirective::MD_Define)
+ {
+ std::string macro_expansion = "#define ";
+ macro_expansion.append(mi->first->getName().str().c_str());
+
+ if (clang::MacroInfo *macro_info = mi->second.getLatest()->getMacroInfo())
+ {
+ if (macro_info->isFunctionLike())
+ {
+ macro_expansion.append("(");
+
+ bool first_arg = true;
+
+ for (clang::MacroInfo::arg_iterator ai = macro_info->arg_begin(),
+ ae = macro_info->arg_end();
+ ai != ae;
+ ++ai)
+ {
+ if (!first_arg)
+ {
+ macro_expansion.append(", ");
+ }
+ else
+ {
+ first_arg = false;
+ }
+
+ macro_expansion.append((*ai)->getName().str());
+ }
+
+ if (macro_info->isC99Varargs())
+ {
+ if (first_arg)
+ {
+ macro_expansion.append("...");
+ }
+ else
+ {
+ macro_expansion.append(", ...");
+ }
+ }
+ else if (macro_info->isGNUVarargs())
+ {
+ macro_expansion.append("...");
+ }
+
+ macro_expansion.append(")");
+ }
+
+ macro_expansion.append(" ");
+
+ bool first_token = true;
+
+ for (clang::MacroInfo::tokens_iterator ti = macro_info->tokens_begin(),
+ te = macro_info->tokens_end();
+ ti != te;
+ ++ti)
+ {
+ if (!first_token)
+ {
+ macro_expansion.append(" ");
+ }
+ else
+ {
+ first_token = false;
+ }
+
+ if (ti->isLiteral())
+ {
+ if (const char *literal_data = ti->getLiteralData())
+ {
+ std::string token_str(literal_data, ti->getLength());
+ macro_expansion.append(token_str);
+ }
+ else
+ {
+ bool invalid = false;
+ const char *literal_source = m_compiler_instance->getSourceManager().getCharacterData(ti->getLocation(), &invalid);
+
+ if (invalid)
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ assert(!"Unhandled token kind");
+#endif
+ macro_expansion.append("<unknown literal value>");
+ }
+ else
+ {
+ macro_expansion.append(std::string(literal_source, ti->getLength()));
+ }
+ }
+ }
+ else if (const char *punctuator_spelling = clang::tok::getPunctuatorSpelling(ti->getKind()))
+ {
+ macro_expansion.append(punctuator_spelling);
+ }
+ else if (const char *keyword_spelling = clang::tok::getKeywordSpelling(ti->getKind()))
+ {
+ macro_expansion.append(keyword_spelling);
+ }
+ else
+ {
+ switch (ti->getKind())
+ {
+ case clang::tok::TokenKind::identifier:
+ macro_expansion.append(ti->getIdentifierInfo()->getName().str());
+ break;
+ case clang::tok::TokenKind::raw_identifier:
+ macro_expansion.append(ti->getRawIdentifier().str());
+ default:
+ macro_expansion.append(ti->getName());
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ assert(!"#define with no macro info");
+#endif
+ }
+
+ if (handler(macro_expansion))
+ {
+ return;
+ }
+ }
+ }
+}
+
ClangModulesDeclVendorImpl::~ClangModulesDeclVendorImpl()
{
}
@@ -308,6 +666,18 @@ ClangModulesDeclVendor::Create(Target &target)
compiler_invocation_arguments.push_back(module_cache_argument);
}
+ FileSpecList &module_search_paths = target.GetClangModuleSearchPaths();
+
+ for (size_t spi = 0, spe = module_search_paths.GetSize(); spi < spe; ++spi)
+ {
+ const FileSpec &search_path = module_search_paths.GetFileSpecAtIndex(spi);
+
+ std::string search_path_argument = "-I";
+ search_path_argument.append(search_path.GetPath());
+
+ compiler_invocation_arguments.push_back(search_path_argument);
+ }
+
{
FileSpec clang_resource_dir = GetResourceDir();
diff --git a/source/Expression/ClangUserExpression.cpp b/source/Expression/ClangUserExpression.cpp
index 55148462bbc0..661bab0e4b43 100644
--- a/source/Expression/ClangUserExpression.cpp
+++ b/source/Expression/ClangUserExpression.cpp
@@ -26,6 +26,8 @@
#include "lldb/Expression/ClangExpressionDeclMap.h"
#include "lldb/Expression/ClangExpressionParser.h"
#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/ClangModulesDeclVendor.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
#include "lldb/Expression/ClangUserExpression.h"
#include "lldb/Expression/ExpressionSourceCode.h"
#include "lldb/Expression/IRExecutionUnit.h"
@@ -70,9 +72,9 @@ ClangUserExpression::ClangUserExpression (const char *expr,
m_result_synthesizer(),
m_jit_module_wp(),
m_enforce_valid_object (true),
- m_cplusplus (false),
- m_objectivec (false),
- m_static_method(false),
+ m_in_cplusplus_method (false),
+ m_in_objectivec_method (false),
+ m_in_static_method(false),
m_needs_object_ptr (false),
m_const_object (false),
m_target (NULL),
@@ -194,7 +196,7 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
}
}
- m_cplusplus = true;
+ m_in_cplusplus_method = true;
m_needs_object_ptr = true;
}
}
@@ -225,17 +227,17 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
}
}
- m_objectivec = true;
+ m_in_objectivec_method = true;
m_needs_object_ptr = true;
if (!method_decl->isInstanceMethod())
- m_static_method = true;
+ m_in_static_method = true;
}
}
else if (clang::FunctionDecl *function_decl = llvm::dyn_cast<clang::FunctionDecl>(decl_context))
{
// We might also have a function that said in the debug information that it captured an
- // object pointer. The best way to deal with getting to the ivars at present it by pretending
+ // object pointer. The best way to deal with getting to the ivars at present is 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.
@@ -268,7 +270,7 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
}
}
- m_cplusplus = true;
+ m_in_cplusplus_method = true;
m_needs_object_ptr = true;
}
else if (language == lldb::eLanguageTypeObjC)
@@ -317,7 +319,7 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
}
else if (self_clang_type.IsObjCObjectPointerType())
{
- m_objectivec = true;
+ m_in_objectivec_method = true;
m_needs_object_ptr = true;
}
else
@@ -328,7 +330,7 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
}
else
{
- m_objectivec = true;
+ m_in_objectivec_method = true;
m_needs_object_ptr = true;
}
}
@@ -452,18 +454,51 @@ ClangUserExpression::Parse (Stream &error_stream,
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()));
+ std::string prefix = m_expr_prefix;
+
+ if (ClangModulesDeclVendor *decl_vendor = m_target->GetClangModulesDeclVendor())
+ {
+ const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = m_target->GetPersistentVariables().GetHandLoadedClangModules();
+ ClangModulesDeclVendor::ModuleVector modules_for_macros;
+
+ for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules)
+ {
+ modules_for_macros.push_back(module);
+ }
+ if (m_target->GetEnableAutoImportClangModules())
+ {
+ if (StackFrame *frame = exe_ctx.GetFramePtr())
+ {
+ if (Block *block = frame->GetFrameBlock())
+ {
+ SymbolContext sc;
+
+ block->CalculateSymbolContext(&sc);
+
+ if (sc.comp_unit)
+ {
+ StreamString error_stream;
+
+ decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros, error_stream);
+ }
+ }
+ }
+ }
+ }
+
+ std::unique_ptr<ExpressionSourceCode> source_code (ExpressionSourceCode::CreateWrapped(prefix.c_str(), m_expr_text.c_str()));
+
lldb::LanguageType lang_type;
- if (m_cplusplus)
+ if (m_in_cplusplus_method)
lang_type = lldb::eLanguageTypeC_plus_plus;
- else if(m_objectivec)
+ else if (m_in_objectivec_method)
lang_type = lldb::eLanguageTypeObjC;
else
lang_type = lldb::eLanguageTypeC;
- if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_static_method, exe_ctx))
+ if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_in_static_method, exe_ctx))
{
error_stream.PutCString ("error: couldn't construct expression body");
return false;
@@ -666,11 +701,11 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
{
ConstString object_name;
- if (m_cplusplus)
+ if (m_in_cplusplus_method)
{
object_name.SetCString("this");
}
- else if (m_objectivec)
+ else if (m_in_objectivec_method)
{
object_name.SetCString("self");
}
@@ -690,7 +725,7 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
object_ptr = 0;
}
- if (m_objectivec)
+ if (m_in_objectivec_method)
{
ConstString cmd_name("_cmd");
@@ -799,7 +834,7 @@ lldb::ExpressionResults
ClangUserExpression::Execute (Stream &error_stream,
ExecutionContext &exe_ctx,
const EvaluateExpressionOptions& options,
- ClangUserExpression::ClangUserExpressionSP &shared_ptr_to_me,
+ lldb::ClangUserExpressionSP &shared_ptr_to_me,
lldb::ClangExpressionVariableSP &result)
{
// The expression log is quite verbose, and if you're just tracking the execution of the
@@ -841,7 +876,7 @@ ClangUserExpression::Execute (Stream &error_stream,
{
args.push_back(object_ptr);
- if (m_objectivec)
+ if (m_in_objectivec_method)
args.push_back(cmd_ptr);
}
@@ -878,7 +913,7 @@ ClangUserExpression::Execute (Stream &error_stream,
if (m_needs_object_ptr) {
args.push_back(object_ptr);
- if (m_objectivec)
+ if (m_in_objectivec_method)
args.push_back(cmd_ptr);
}
@@ -1008,7 +1043,22 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
if (process == NULL || !process->CanJIT())
execution_policy = eExecutionPolicyNever;
- ClangUserExpressionSP user_expression_sp (new ClangUserExpression (expr_cstr, expr_prefix, language, desired_type));
+ const char *full_prefix = NULL;
+ const char *option_prefix = options.GetPrefix();
+ std::string full_prefix_storage;
+ if (expr_prefix && option_prefix)
+ {
+ full_prefix_storage.assign(expr_prefix);
+ full_prefix_storage.append(option_prefix);
+ if (!full_prefix_storage.empty())
+ full_prefix = full_prefix_storage.c_str();
+ }
+ else if (expr_prefix)
+ full_prefix = expr_prefix;
+ else
+ full_prefix = option_prefix;
+
+ lldb::ClangUserExpressionSP user_expression_sp (new ClangUserExpression (expr_cstr, full_prefix, language, desired_type));
StreamString error_stream;
@@ -1031,10 +1081,11 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
keep_expression_in_memory,
generate_debug_info))
{
+ execution_results = lldb::eExpressionParseError;
if (error_stream.GetString().empty())
- error.SetExpressionError (lldb::eExpressionParseError, "expression failed to parse, unknown error");
+ error.SetExpressionError (execution_results, "expression failed to parse, unknown error");
else
- error.SetExpressionError (lldb::eExpressionParseError, error_stream.GetString().c_str());
+ error.SetExpressionError (execution_results, error_stream.GetString().c_str());
}
else
{
diff --git a/source/Expression/DWARFExpression.cpp b/source/Expression/DWARFExpression.cpp
index 827bddd8e7bc..9307c84510b0 100644
--- a/source/Expression/DWARFExpression.cpp
+++ b/source/Expression/DWARFExpression.cpp
@@ -30,8 +30,6 @@
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
-#include "lldb/lldb-private-log.h"
-
#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
@@ -611,7 +609,6 @@ DWARFExpression::DumpLocation (Stream *s, lldb::offset_t offset, lldb::offset_t
case DW_OP_call_ref: // 0x9a DWARF3 1 4- or 8-byte offset of DIE
s->Printf("DW_OP_call_ref(0x%8.8" PRIx64 ")", m_data.GetAddress(&offset));
break;
-// case DW_OP_form_tls_address: s << "form_tls_address"; break; // 0x9b DWARF3
// case DW_OP_call_frame_cfa: s << "call_frame_cfa"; break; // 0x9c DWARF3
// case DW_OP_bit_piece: // 0x9d DWARF3 2
// s->Printf("DW_OP_bit_piece(0x%x, 0x%x)", m_data.GetULEB128(&offset), m_data.GetULEB128(&offset));
@@ -624,6 +621,9 @@ DWARFExpression::DumpLocation (Stream *s, lldb::offset_t offset, lldb::offset_t
// case DW_OP_APPLE_array_ref:
// s->PutCString("DW_OP_APPLE_array_ref");
// break;
+ case DW_OP_form_tls_address:
+ s->PutCString("DW_OP_form_tls_address"); // 0x9b
+ break;
case DW_OP_GNU_push_tls_address:
s->PutCString("DW_OP_GNU_push_tls_address"); // 0xe0
break;
@@ -2198,6 +2198,13 @@ DWARFExpression::Evaluate
// constant.
//----------------------------------------------------------------------
case DW_OP_bra:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_bra.");
+ return false;
+ }
+ else
{
tmp = stack.back();
stack.pop_back();
@@ -2890,17 +2897,24 @@ DWARFExpression::Evaluate
break;
//----------------------------------------------------------------------
- // OPCODE: DW_OP_GNU_push_tls_address
+ // OPCODE: DW_OP_form_tls_address (or the old pre-DWARFv3 vendor extension opcode, DW_OP_GNU_push_tls_address)
// OPERANDS: none
// DESCRIPTION: Pops a TLS offset from the stack, converts it to
- // an absolute value, and pushes it back on.
+ // an address in the current thread's thread-local storage block,
+ // and pushes it on the stack.
//----------------------------------------------------------------------
+ case DW_OP_form_tls_address:
case DW_OP_GNU_push_tls_address:
{
if (stack.size() < 1)
{
if (error_ptr)
- error_ptr->SetErrorString("DW_OP_GNU_push_tls_address needs an argument.");
+ {
+ if (op == DW_OP_form_tls_address)
+ error_ptr->SetErrorString("DW_OP_form_tls_address needs an argument.");
+ else
+ error_ptr->SetErrorString("DW_OP_GNU_push_tls_address needs an argument.");
+ }
return false;
}
diff --git a/source/Expression/ExpressionSourceCode.cpp b/source/Expression/ExpressionSourceCode.cpp
index b3f335f1b314..9a42510d0a24 100644
--- a/source/Expression/ExpressionSourceCode.cpp
+++ b/source/Expression/ExpressionSourceCode.cpp
@@ -10,24 +10,33 @@
#include "lldb/Expression/ExpressionSourceCode.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/ClangModulesDeclVendor.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
+#include "lldb/Symbol/Block.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
+#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
using namespace lldb_private;
const char *
ExpressionSourceCode::g_expression_prefix = R"(
-#undef NULL
-#undef Nil
-#undef nil
-#undef YES
-#undef NO
+#ifndef NULL
#define NULL (__null)
+#endif
+#ifndef Nil
#define Nil (__null)
+#endif
+#ifndef nil
#define nil (__null)
+#endif
+#ifndef YES
#define YES ((BOOL)1)
+#endif
+#ifndef NO
#define NO ((BOOL)0)
+#endif
typedef __INT8_TYPE__ int8_t;
typedef __UINT8_TYPE__ uint8_t;
typedef __INT16_TYPE__ int16_t;
@@ -51,7 +60,7 @@ extern "C"
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 ("ios-simulator");
+ std::string module_macros;
if (Target *target = exe_ctx.GetTargetPtr())
{
@@ -63,12 +72,51 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
{
if (lldb::PlatformSP platform_sp = target->GetPlatform())
{
+ static ConstString g_platform_ios_simulator ("ios-simulator");
if (platform_sp->GetPluginName() == g_platform_ios_simulator)
{
target_specific_defines = "typedef bool BOOL;\n";
}
}
}
+
+ if (ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor())
+ {
+ const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = target->GetPersistentVariables().GetHandLoadedClangModules();
+ ClangModulesDeclVendor::ModuleVector modules_for_macros;
+
+ for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules)
+ {
+ modules_for_macros.push_back(module);
+ }
+
+ if (target->GetEnableAutoImportClangModules())
+ {
+ if (StackFrame *frame = exe_ctx.GetFramePtr())
+ {
+ if (Block *block = frame->GetFrameBlock())
+ {
+ SymbolContext sc;
+
+ block->CalculateSymbolContext(&sc);
+
+ if (sc.comp_unit)
+ {
+ StreamString error_stream;
+
+ decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros, error_stream);
+ }
+ }
+ }
+ }
+
+ decl_vendor->ForEachMacro(modules_for_macros, [&module_macros] (const std::string &expansion) -> bool {
+ module_macros.append(expansion);
+ module_macros.append("\n");
+ return false;
+ });
+ }
+
}
if (m_wrap)
@@ -85,37 +133,31 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
StreamString wrap_stream;
+ wrap_stream.Printf("%s\n%s\n%s\n%s\n",
+ module_macros.c_str(),
+ g_expression_prefix,
+ target_specific_defines,
+ m_prefix.c_str());
+
switch (wrapping_language)
{
default:
break;
case lldb::eLanguageTypeC:
- wrap_stream.Printf("%s \n"
- "%s \n"
- "%s \n"
- "void \n"
+ wrap_stream.Printf("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());
break;
case lldb::eLanguageTypeC_plus_plus:
- wrap_stream.Printf("%s \n"
- "%s \n"
- "%s \n"
- "void \n"
+ wrap_stream.Printf("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" : ""),
m_body.c_str());
@@ -123,10 +165,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
case lldb::eLanguageTypeObjC:
if (static_method)
{
- wrap_stream.Printf("%s \n"
- "%s \n"
- "%s \n"
- "@interface $__lldb_objc_class ($__lldb_category) \n"
+ wrap_stream.Printf("@interface $__lldb_objc_class ($__lldb_category) \n"
"+(void)%s:(void *)$__lldb_arg; \n"
"@end \n"
"@implementation $__lldb_objc_class ($__lldb_category) \n"
@@ -135,19 +174,13 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
" %s; \n"
"} \n"
"@end \n",
- g_expression_prefix,
- target_specific_defines,
- m_prefix.c_str(),
m_name.c_str(),
m_name.c_str(),
m_body.c_str());
}
else
{
- wrap_stream.Printf("%s \n"
- "%s \n"
- "%s \n"
- "@interface $__lldb_objc_class ($__lldb_category) \n"
+ wrap_stream.Printf("@interface $__lldb_objc_class ($__lldb_category) \n"
"-(void)%s:(void *)$__lldb_arg; \n"
"@end \n"
"@implementation $__lldb_objc_class ($__lldb_category) \n"
@@ -156,9 +189,6 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
" %s; \n"
"} \n"
"@end \n",
- g_expression_prefix,
- target_specific_defines,
- m_prefix.c_str(),
m_name.c_str(),
m_name.c_str(),
m_body.c_str());
diff --git a/source/Expression/IRExecutionUnit.cpp b/source/Expression/IRExecutionUnit.cpp
index 9ca9e25907b6..7232685e4f41 100644
--- a/source/Expression/IRExecutionUnit.cpp
+++ b/source/Expression/IRExecutionUnit.cpp
@@ -11,6 +11,8 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Debugger.h"
@@ -18,9 +20,11 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
+#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
using namespace lldb_private;
@@ -584,7 +588,7 @@ IRExecutionUnit::MemoryManager::allocateCodeSection(uintptr_t Size,
if (log)
{
log->Printf("IRExecutionUnit::allocateCodeSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p",
- (uint64_t)Size, Alignment, SectionID, return_value);
+ (uint64_t)Size, Alignment, SectionID, (void *)return_value);
}
return return_value;
@@ -601,8 +605,11 @@ IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size,
uint8_t *return_value = m_default_mm_ap->allocateDataSection(Size, Alignment, SectionID, SectionName, IsReadOnly);
+ uint32_t permissions = lldb::ePermissionsReadable;
+ if (!IsReadOnly)
+ permissions |= lldb::ePermissionsWritable;
m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
- lldb::ePermissionsReadable | (IsReadOnly ? 0 : lldb::ePermissionsWritable),
+ permissions,
GetSectionTypeFromSectionName (SectionName, AllocationKind::Data),
Size,
Alignment,
@@ -611,7 +618,7 @@ IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size,
if (log)
{
log->Printf("IRExecutionUnit::allocateDataSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p",
- (uint64_t)Size, Alignment, SectionID, return_value);
+ (uint64_t)Size, Alignment, SectionID, (void *)return_value);
}
return return_value;
@@ -669,20 +676,10 @@ IRExecutionUnit::MemoryManager::getSymbolAddress(const std::string &Name)
SymbolContext sym_ctx;
sc_list.GetContextAtIndex(i, sym_ctx);
- if (sym_ctx.symbol->GetType() == lldb::eSymbolTypeUndefined)
- continue;
-
- const Address *sym_address = &sym_ctx.symbol->GetAddress();
-
- if (!sym_address || !sym_address->IsValid())
- continue;
-
symbol_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target_sp);
-
+
if (symbol_load_addr == LLDB_INVALID_ADDRESS)
- {
symbol_load_addr = sym_ctx.symbol->GetAddress().GetLoadAddress(target_sp.get());
- }
}
if (symbol_load_addr == LLDB_INVALID_ADDRESS && process_sp && name_cs)
diff --git a/source/Expression/IRForTarget.cpp b/source/Expression/IRForTarget.cpp
index 42390b35fdde..11bc011d6d64 100644
--- a/source/Expression/IRForTarget.cpp
+++ b/source/Expression/IRForTarget.cpp
@@ -16,7 +16,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
-#include "llvm/PassManager.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/ValueSymbolTable.h"
@@ -35,6 +35,7 @@
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
#include <map>
@@ -59,7 +60,8 @@ IRForTarget::FunctionValueCache::~FunctionValueCache()
{
}
-llvm::Value *IRForTarget::FunctionValueCache::GetValue(llvm::Function *function)
+llvm::Value *
+IRForTarget::FunctionValueCache::GetValue(llvm::Function *function)
{
if (!m_values.count(function))
{
@@ -70,7 +72,8 @@ llvm::Value *IRForTarget::FunctionValueCache::GetValue(llvm::Function *function)
return m_values[function];
}
-lldb::addr_t IRForTarget::StaticDataAllocator::Allocate()
+lldb::addr_t
+IRForTarget::StaticDataAllocator::Allocate()
{
lldb_private::Error err;
@@ -85,7 +88,14 @@ lldb::addr_t IRForTarget::StaticDataAllocator::Allocate()
return m_allocation;
}
-static llvm::Value *FindEntryInstruction (llvm::Function *function)
+lldb::TargetSP
+IRForTarget::StaticDataAllocator::GetTarget()
+{
+ return m_execution_unit.GetTarget();
+}
+
+static llvm::Value *
+FindEntryInstruction (llvm::Function *function)
{
if (function->empty())
return NULL;
@@ -217,44 +227,45 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
{
if (!m_decl_map->GetFunctionInfo (fun_decl, fun_addr))
{
- lldb_private::ConstString altnernate_name;
+ std::vector<lldb_private::ConstString> alternates;
bool found_it = m_decl_map->GetFunctionAddress (name, fun_addr);
if (!found_it)
{
- // Check for an alternate mangling for "std::basic_string<char>"
- // that is part of the itanium C++ name mangling scheme
- const char *name_cstr = name.GetCString();
- if (name_cstr && strncmp(name_cstr, "_ZNKSbIcE", strlen("_ZNKSbIcE")) == 0)
+ if (log)
+ log->Printf("Address of function \"%s\" not found.\n", name.GetCString());
+ // Check for an alternate mangling for names from the standard library.
+ // For example, "std::basic_string<...>" has an alternate mangling scheme per
+ // the Itanium C++ ABI.
+ lldb::ProcessSP process_sp = m_data_allocator.GetTarget()->GetProcessSP();
+ if (process_sp)
{
- std::string alternate_mangling("_ZNKSs");
- alternate_mangling.append (name_cstr + strlen("_ZNKSbIcE"));
- altnernate_name.SetCString(alternate_mangling.c_str());
- found_it = m_decl_map->GetFunctionAddress (altnernate_name, fun_addr);
+ lldb_private::CPPLanguageRuntime *cpp_runtime = process_sp->GetCPPLanguageRuntime();
+ if (cpp_runtime && cpp_runtime->GetAlternateManglings(name, alternates))
+ {
+ for (size_t i = 0; i < alternates.size(); ++i)
+ {
+ const lldb_private::ConstString &alternate_name = alternates[i];
+ if (log)
+ log->Printf("Looking up address of function \"%s\" with alternate name \"%s\"",
+ name.GetCString(), alternate_name.GetCString());
+ if ((found_it = m_decl_map->GetFunctionAddress (alternate_name, fun_addr)))
+ {
+ if (log)
+ log->Printf("Found address of function \"%s\" with alternate name \"%s\"",
+ name.GetCString(), alternate_name.GetCString());
+ break;
+ }
+ }
+ }
}
}
if (!found_it)
{
lldb_private::Mangled mangled_name(name);
- lldb_private::Mangled alt_mangled_name(altnernate_name);
- if (log)
- {
- if (alt_mangled_name)
- log->Printf("Function \"%s\" (alternate name \"%s\") has no address",
- mangled_name.GetName().GetCString(),
- alt_mangled_name.GetName().GetCString());
- else
- log->Printf("Function \"%s\" had no address",
- mangled_name.GetName().GetCString());
- }
-
if (m_error_stream)
{
- if (alt_mangled_name)
- m_error_stream->Printf("error: call to a function '%s' (alternate name '%s') that is not present in the target\n",
- mangled_name.GetName().GetCString(),
- alt_mangled_name.GetName().GetCString());
- else if (mangled_name.GetMangledName())
+ if (mangled_name.GetMangledName())
m_error_stream->Printf("error: call to a function '%s' ('%s') that is not present in the target\n",
mangled_name.GetName().GetCString(),
mangled_name.GetMangledName().GetCString());
@@ -590,7 +601,10 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
&result_decl->getASTContext());
}
- if (m_result_type.GetBitSize(nullptr) == 0)
+
+ lldb::TargetSP target_sp (m_data_allocator.GetTarget());
+ lldb_private::ExecutionContext exe_ctx (target_sp, true);
+ if (m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()) == 0)
{
lldb_private::StreamString type_desc_stream;
m_result_type.DumpTypeDescription(&type_desc_stream);
@@ -1345,7 +1359,7 @@ IRForTarget::MaterializeInitializer (uint8_t *data, Constant *initializer)
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (log && log->GetVerbose())
- log->Printf(" MaterializeInitializer(%p, %s)", data, PrintValue(initializer).c_str());
+ log->Printf(" MaterializeInitializer(%p, %s)", (void *)data, PrintValue(initializer).c_str());
Type *initializer_type = initializer->getType();
@@ -1501,7 +1515,7 @@ IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr)
if (name[0] == '$')
{
- // The $__lldb_expr_result name indicates the the return value has allocated as
+ // The $__lldb_expr_result name indicates the return value has allocated as
// a static variable. Per the comment at ASTResultSynthesizer::SynthesizeBodyResult,
// accesses to this static variable need to be redirected to the result of dereferencing
// a pointer that is passed in as one of the arguments.
@@ -2194,7 +2208,7 @@ IRForTarget::UnfoldConstant(Constant *old_constant,
ArrayRef <Value*> indices(index_vector);
- return GetElementPtrInst::Create(ptr, indices, "", llvm::cast<Instruction>(entry_instruction_finder.GetValue(function)));
+ return GetElementPtrInst::Create(nullptr, ptr, indices, "", llvm::cast<Instruction>(entry_instruction_finder.GetValue(function)));
});
if (!UnfoldConstant(constant_expr, get_element_pointer_maker, entry_instruction_finder))
@@ -2381,7 +2395,8 @@ IRForTarget::ReplaceVariables (Function &llvm_function)
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,
+ GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create(nullptr,
+ argument,
offset_int,
"",
entry_instruction);
@@ -2441,11 +2456,14 @@ IRForTarget::BuildRelocation(llvm::Type *type, uint64_t offset)
offset_array[0] = offset_int;
llvm::ArrayRef<llvm::Constant *> offsets(offset_array, 1);
+ llvm::Type *char_type = llvm::Type::getInt8Ty(m_module->getContext());
+ llvm::Type *char_pointer_type = char_type->getPointerTo();
- llvm::Constant *reloc_getelementptr = ConstantExpr::getGetElementPtr(m_reloc_placeholder, offsets);
- llvm::Constant *reloc_getbitcast = ConstantExpr::getBitCast(reloc_getelementptr, type);
+ llvm::Constant *reloc_placeholder_bitcast = ConstantExpr::getBitCast(m_reloc_placeholder, char_pointer_type);
+ llvm::Constant *reloc_getelementptr = ConstantExpr::getGetElementPtr(char_type, reloc_placeholder_bitcast, offsets);
+ llvm::Constant *reloc_bitcast = ConstantExpr::getBitCast(reloc_getelementptr, type);
- return reloc_getbitcast;
+ return reloc_bitcast;
}
bool
diff --git a/source/Expression/Materializer.cpp b/source/Expression/Materializer.cpp
index f1f2f99eed5e..ef01feea2a4c 100644
--- a/source/Expression/Materializer.cpp
+++ b/source/Expression/Materializer.cpp
@@ -12,6 +12,7 @@
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
#include "lldb/Expression/Materializer.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/Symbol.h"
@@ -1051,7 +1052,7 @@ public:
m_symbol.GetName().AsCString());
}
- Address &sym_address = m_symbol.GetAddress();
+ const Address sym_address = m_symbol.GetAddress();
ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
diff --git a/source/Host/common/Editline.cpp b/source/Host/common/Editline.cpp
index a127d58b2767..ed67d0c2c2b3 100644
--- a/source/Host/common/Editline.cpp
+++ b/source/Host/common/Editline.cpp
@@ -20,6 +20,7 @@
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/Utility/LLDBAssert.h"
using namespace lldb_private;
using namespace lldb_private::line_editor;
@@ -192,9 +193,9 @@ namespace lldb_private
{
if (m_path.empty() && m_history && !m_prefix.empty())
{
- std::string parent_path = FileSpec ("~/.lldb", true).GetPath();
+ FileSpec parent_path{"~/.lldb", true};
char history_path[PATH_MAX];
- if (FileSystem::MakeDirectory(parent_path.c_str(), lldb::eFilePermissionsDirectoryDefault).Success())
+ if (FileSystem::MakeDirectory(parent_path, lldb::eFilePermissionsDirectoryDefault).Success())
{
snprintf (history_path, sizeof (history_path), "~/.lldb/%s-history", m_prefix.c_str());
}
@@ -581,9 +582,22 @@ Editline::GetCharacter (EditLineCharType * c)
{
lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
char ch = 0;
- m_editor_getting_char = true;
+
+ // This mutex is locked by our caller (GetLine). Unlock it while we read a character
+ // (blocking operation), so we do not hold the mutex indefinitely. This gives a chance
+ // for someone to interrupt us. After Read returns, immediately lock the mutex again and
+ // check if we were interrupted.
+ m_output_mutex.Unlock();
int read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
- m_editor_getting_char = false;
+ m_output_mutex.Lock();
+ if (m_editor_status == EditorStatus::Interrupted)
+ {
+ while (read_count > 0 && status == lldb::eConnectionStatusSuccess)
+ read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
+ lldbassert(status == lldb::eConnectionStatusInterrupted);
+ return 0;
+ }
+
if (read_count)
{
#if LLDB_EDITLINE_USE_WCHAR
@@ -594,7 +608,7 @@ Editline::GetCharacter (EditLineCharType * c)
return 1;
#else
*c = ch;
- if(*c != EOF)
+ if(ch != (char)EOF)
return 1;
#endif
}
@@ -602,14 +616,12 @@ Editline::GetCharacter (EditLineCharType * c)
{
switch (status)
{
- case lldb::eConnectionStatusInterrupted:
- m_editor_status = EditorStatus::Interrupted;
- printf ("^C\n");
- return 0;
-
case lldb::eConnectionStatusSuccess: // Success
break;
+ case lldb::eConnectionStatusInterrupted:
+ lldbassert(0 && "Interrupts should have been handled above.");
+
case lldb::eConnectionStatusError: // Check GetError() for details
case lldb::eConnectionStatusTimedOut: // Request timed out
case lldb::eConnectionStatusEndOfFile: // End-of-file encountered
@@ -711,7 +723,7 @@ Editline::BreakLineCommand (int ch)
unsigned char
Editline::DeleteNextCharCommand (int ch)
{
- LineInfoW * info = (LineInfoW *)el_wline (m_editline);
+ LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
// Just delete the next character normally if possible
if (info->cursor < info->lastchar)
@@ -755,7 +767,7 @@ Editline::DeleteNextCharCommand (int ch)
unsigned char
Editline::DeletePreviousCharCommand (int ch)
{
- LineInfoW * info = (LineInfoW *)el_wline (m_editline);
+ LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
// Just delete the previous character normally when not at the start of a line
if (info->cursor > info->buffer)
@@ -861,7 +873,7 @@ Editline::FixIndentationCommand (int ch)
StringList lines = GetInputAsStringList (m_current_line_index + 1);
// Determine the cursor position
- LineInfoW * info = (LineInfoW *)el_wline (m_editline);
+ LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
int cursor_position = info->cursor - info->buffer;
int indent_correction = m_fix_indentation_callback (this, lines, cursor_position, m_fix_indentation_callback_baton);
@@ -887,7 +899,7 @@ Editline::RevertLineCommand (int ch)
el_winsertstr (m_editline, m_input_lines[m_current_line_index].c_str());
if (m_revert_cursor_index >= 0)
{
- LineInfoW * info = (LineInfoW *)el_wline (m_editline);
+ LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
info->cursor = info->buffer + m_revert_cursor_index;
if (info->cursor > info->lastchar)
{
@@ -1252,41 +1264,31 @@ Editline::GetCurrentLine()
return m_current_line_index;
}
-void
-Editline::Hide()
-{
- // Make sure we're at a stable location waiting for input
- while (m_editor_status == EditorStatus::Editing && !m_editor_getting_char)
- {
- usleep(100000);
- }
-
- // Clear the existing input
- if (m_editor_status == EditorStatus::Editing)
- {
- MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
- fprintf(m_output_file, ANSI_CLEAR_BELOW);
- }
-}
-
-void
-Editline::Refresh()
+bool
+Editline::Interrupt()
{
- if (m_editor_status == EditorStatus::Editing)
- {
- DisplayInput();
- MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ bool result = true;
+ Mutex::Locker locker(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing) {
+ fprintf(m_output_file, "^C\n");
+ result = m_input_connection.InterruptRead();
}
+ m_editor_status = EditorStatus::Interrupted;
+ return result;
}
bool
-Editline::Interrupt()
+Editline::Cancel()
{
- if (m_editor_status == EditorStatus::Editing)
- {
- return m_input_connection.InterruptRead();
+ bool result = true;
+ Mutex::Locker locker(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing) {
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ fprintf(m_output_file, ANSI_CLEAR_BELOW);
+ result = m_input_connection.InterruptRead();
}
- return false; // Interrupt not handled as we weren't getting a line or lines
+ m_editor_status = EditorStatus::Interrupted;
+ return result;
}
void
@@ -1321,14 +1323,23 @@ Editline::GetLine (std::string &line, bool &interrupted)
m_input_lines = std::vector<EditLineStringType>();
m_input_lines.insert (m_input_lines.begin(), EditLineConstString(""));
+ Mutex::Locker locker(m_output_mutex);
+
+ lldbassert(m_editor_status != EditorStatus::Editing);
+ if (m_editor_status == EditorStatus::Interrupted)
+ {
+ m_editor_status = EditorStatus::Complete;
+ interrupted = true;
+ return true;
+ }
+
SetCurrentLine (0);
m_in_history = false;
m_editor_status = EditorStatus::Editing;
- m_editor_getting_char = false;
m_revert_cursor_index = -1;
#ifdef USE_SETUPTERM_WORKAROUND
- setupterm((char *)0, fileno(m_output_file), (int *)0);
+ setupterm((char *)0, fileno(m_output_file), (int *)0);
#endif
int count;
@@ -1366,12 +1377,12 @@ Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted)
m_input_lines = std::vector<EditLineStringType>();
m_input_lines.insert (m_input_lines.begin(), EditLineConstString(""));
+ Mutex::Locker locker(m_output_mutex);
// Begin the line editing loop
DisplayInput();
SetCurrentLine (0);
MoveCursor (CursorLocation::BlockEnd, CursorLocation::BlockStart);
m_editor_status = EditorStatus::Editing;
- m_editor_getting_char = false;
m_in_history = false;
m_revert_cursor_index = -1;
@@ -1396,3 +1407,21 @@ Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted)
}
return m_editor_status != EditorStatus::EndOfInput;
}
+
+void
+Editline::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+ Mutex::Locker locker(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing)
+ {
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ fprintf(m_output_file, ANSI_CLEAR_BELOW);
+ }
+ stream->Write (s, len);
+ stream->Flush();
+ if (m_editor_status == EditorStatus::Editing)
+ {
+ DisplayInput();
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ }
+}
diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp
index 946f3dd6fef5..a3420bff65f5 100644
--- a/source/Host/common/File.cpp
+++ b/source/Host/common/File.cpp
@@ -325,12 +325,12 @@ File::Open (const char *path, uint32_t options, uint32_t permissions)
}
uint32_t
-File::GetPermissions (const char *path, Error &error)
+File::GetPermissions(const FileSpec &file_spec, Error &error)
{
- if (path && path[0])
+ if (file_spec)
{
struct stat file_stats;
- if (::stat (path, &file_stats) == -1)
+ if (::stat(file_spec.GetCString(), &file_stats) == -1)
error.SetErrorToErrno();
else
{
@@ -339,12 +339,7 @@ File::GetPermissions (const char *path, Error &error)
}
}
else
- {
- if (path)
- error.SetErrorString ("invalid path");
- else
- error.SetErrorString ("empty path");
- }
+ error.SetErrorString ("empty file spec");
return 0;
}
@@ -595,10 +590,49 @@ File::Sync ()
return error;
}
+#if defined (__APPLE__)
+// Darwin kernels only can read/write <= INT_MAX bytes
+#define MAX_READ_SIZE INT_MAX
+#define MAX_WRITE_SIZE INT_MAX
+#endif
+
Error
File::Read (void *buf, size_t &num_bytes)
{
Error error;
+
+#if defined (MAX_READ_SIZE)
+ if (num_bytes > MAX_READ_SIZE)
+ {
+ uint8_t *p = (uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes read to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0)
+ {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_READ_SIZE)
+ curr_num_bytes = MAX_READ_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Read (p + num_bytes, curr_num_bytes);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
ssize_t bytes_read = -1;
if (DescriptorIsValid())
{
@@ -642,6 +676,39 @@ Error
File::Write (const void *buf, size_t &num_bytes)
{
Error error;
+
+#if defined (MAX_WRITE_SIZE)
+ if (num_bytes > MAX_WRITE_SIZE)
+ {
+ const uint8_t *p = (const uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes written to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0)
+ {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_WRITE_SIZE)
+ curr_num_bytes = MAX_WRITE_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Write (p + num_bytes, curr_num_bytes);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
ssize_t bytes_written = -1;
if (DescriptorIsValid())
{
@@ -687,8 +754,41 @@ File::Write (const void *buf, size_t &num_bytes)
Error
File::Read (void *buf, size_t &num_bytes, off_t &offset)
{
-#ifndef _WIN32
Error error;
+
+#if defined (MAX_READ_SIZE)
+ if (num_bytes > MAX_READ_SIZE)
+ {
+ uint8_t *p = (uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes read to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0)
+ {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_READ_SIZE)
+ curr_num_bytes = MAX_READ_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Read (p + num_bytes, curr_num_bytes, offset);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
+#ifndef _WIN32
int fd = GetDescriptor();
if (fd != kInvalidDescriptor)
{
@@ -714,15 +814,14 @@ File::Read (void *buf, size_t &num_bytes, off_t &offset)
num_bytes = 0;
error.SetErrorString("invalid file handle");
}
- return error;
#else
long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
SeekFromStart(offset);
- Error error = Read(buf, num_bytes);
+ error = Read(buf, num_bytes);
if (!error.Fail())
SeekFromStart(cur);
- return error;
#endif
+ return error;
}
Error
@@ -746,7 +845,8 @@ File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP
size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0);
std::unique_ptr<DataBufferHeap> data_heap_ap;
- data_heap_ap.reset(new DataBufferHeap(num_bytes_plus_nul_char, '\0'));
+ data_heap_ap.reset(new DataBufferHeap());
+ data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
if (data_heap_ap.get())
{
@@ -783,6 +883,39 @@ Error
File::Write (const void *buf, size_t &num_bytes, off_t &offset)
{
Error error;
+
+#if defined (MAX_WRITE_SIZE)
+ if (num_bytes > MAX_WRITE_SIZE)
+ {
+ const uint8_t *p = (const uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes written to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0)
+ {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_WRITE_SIZE)
+ curr_num_bytes = MAX_WRITE_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Write (p + num_bytes, curr_num_bytes, offset);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
int fd = GetDescriptor();
if (fd != kInvalidDescriptor)
{
@@ -811,7 +944,6 @@ File::Write (const void *buf, size_t &num_bytes, off_t &offset)
if (!error.Fail())
SeekFromStart(cur);
- ssize_t bytes_written = after - cur;
offset = after;
#endif
}
diff --git a/source/Host/common/FileSpec.cpp b/source/Host/common/FileSpec.cpp
index 6a6de53cd311..ceb094b9ede7 100644
--- a/source/Host/common/FileSpec.cpp
+++ b/source/Host/common/FileSpec.cpp
@@ -27,6 +27,7 @@
#include <pwd.h>
#endif
+#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataBufferMemoryMap.h"
#include "lldb/Core/RegularExpression.h"
@@ -46,7 +47,45 @@
using namespace lldb;
using namespace lldb_private;
-static bool
+namespace {
+
+bool
+PathSyntaxIsPosix(FileSpec::PathSyntax syntax)
+{
+ return (syntax == FileSpec::ePathSyntaxPosix ||
+ (syntax == FileSpec::ePathSyntaxHostNative &&
+ FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix));
+}
+
+char
+GetPathSeparator(FileSpec::PathSyntax syntax)
+{
+ return PathSyntaxIsPosix(syntax) ? '/' : '\\';
+}
+
+void
+Normalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax)
+{
+ if (PathSyntaxIsPosix(syntax)) return;
+
+ std::replace(path.begin(), path.end(), '\\', '/');
+ // Windows path can have \\ slashes which can be changed by replace
+ // call above to //. Here we remove the duplicate.
+ auto iter = std::unique ( path.begin(), path.end(),
+ []( char &c1, char &c2 ){
+ return (c1 == '/' && c2 == '/');});
+ path.erase(iter, path.end());
+}
+
+void
+Denormalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax)
+{
+ if (PathSyntaxIsPosix(syntax)) return;
+
+ std::replace(path.begin(), path.end(), '/', '\\');
+}
+
+bool
GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
{
char resolved_path[PATH_MAX];
@@ -55,6 +94,8 @@ GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
return false;
}
+}
+
// Resolves the username part of a path of the form ~user/other/directories, and
// writes the result into dst_path. This will also resolve "~" to the current user.
// If you want to complete "~" to the list of users, pass it to ResolvePartialUsername.
@@ -164,7 +205,20 @@ FileSpec::Resolve (llvm::SmallVectorImpl<char> &path)
ResolveUsername(path);
#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+ // Save a copy of the original path that's passed in
+ llvm::SmallString<PATH_MAX> original_path(path.begin(), path.end());
+
llvm::sys::fs::make_absolute(path);
+
+
+ path.push_back(0); // Be sure we have a nul terminated string
+ path.pop_back();
+ struct stat file_stats;
+ if (::stat (path.data(), &file_stats) != 0)
+ {
+ path.clear();
+ path.append(original_path.begin(), original_path.end());
+ }
}
FileSpec::FileSpec() :
@@ -188,6 +242,21 @@ FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) :
SetFile(pathname, resolve_path, syntax);
}
+FileSpec::FileSpec(const char *pathname, bool resolve_path, ArchSpec arch) :
+ FileSpec{pathname, resolve_path, arch.GetTriple().isOSWindows() ? ePathSyntaxWindows : ePathSyntaxPosix}
+{
+}
+
+FileSpec::FileSpec(const std::string &path, bool resolve_path, PathSyntax syntax) :
+ FileSpec{path.c_str(), resolve_path, syntax}
+{
+}
+
+FileSpec::FileSpec(const std::string &path, bool resolve_path, ArchSpec arch) :
+ FileSpec{path.c_str(), resolve_path, arch}
+{
+}
+
//------------------------------------------------------------------
// Copy constructor
//------------------------------------------------------------------
@@ -233,30 +302,6 @@ FileSpec::operator= (const FileSpec& rhs)
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(), '\\', '/');
- // Windows path can have \\ slashes which can be changed by replace
- // call above to //. Here we remove the duplicate.
- auto iter = std::unique ( path.begin(), path.end(),
- []( char &c1, char &c2 ){
- return (c1 == '/' && c2 == '/');});
- path.erase(iter, 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
@@ -299,6 +344,27 @@ FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax)
m_directory.SetCString(normalized.c_str());
}
+void
+FileSpec::SetFile(const char *pathname, bool resolve, ArchSpec arch)
+{
+ return SetFile(pathname, resolve,
+ arch.GetTriple().isOSWindows()
+ ? ePathSyntaxWindows
+ : ePathSyntaxPosix);
+}
+
+void
+FileSpec::SetFile(const std::string &pathname, bool resolve, PathSyntax syntax)
+{
+ return SetFile(pathname.c_str(), resolve, syntax);
+}
+
+void
+FileSpec::SetFile(const std::string &pathname, bool resolve, ArchSpec arch)
+{
+ return SetFile(pathname.c_str(), resolve, arch);
+}
+
//----------------------------------------------------------------------
// Convert to pointer operator. This allows code to check any FileSpec
// objects to see if they contain anything valid using code such as:
@@ -480,6 +546,14 @@ FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full, bool remove_ba
}
void
+FileSpec::NormalizePath ()
+{
+ ConstString normalized_directory;
+ FileSpec::RemoveBackupDots(m_directory, normalized_directory);
+ m_directory = normalized_directory;
+}
+
+void
FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &result_const_str)
{
const char *input = input_const_str.GetCString();
@@ -545,6 +619,8 @@ FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &res
{
if (had_dots)
{
+ while (before_sep.startswith("//"))
+ before_sep = before_sep.substr(1);
if (!before_sep.empty())
{
result.append(before_sep.data(), before_sep.size());
@@ -590,13 +666,13 @@ FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &res
void
FileSpec::Dump(Stream *s) const
{
- static ConstString g_slash_only ("/");
if (s)
{
- m_directory.Dump(s);
- if (m_directory && m_directory != g_slash_only)
- s->PutChar('/');
- m_filename.Dump(s);
+ std::string path{GetPath(true)};
+ s->PutCString(path.c_str());
+ char path_separator = GetPathSeparator(m_syntax);
+ if (!m_filename && !path.empty() && path.back() != path_separator)
+ s->PutChar(path_separator);
}
}
@@ -718,7 +794,7 @@ FileSpec::GetPermissions () const
{
uint32_t file_permissions = 0;
if (*this)
- FileSystem::GetFilePermissions(GetPath().c_str(), file_permissions);
+ FileSystem::GetFilePermissions(*this, file_permissions);
return file_permissions;
}
@@ -780,26 +856,37 @@ FileSpec::GetPath(char *path, size_t path_max_len, bool denormalize) const
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;
+ ::snprintf(path, path_max_len, "%s", result.c_str());
+ return std::min(path_max_len-1, result.length());
}
std::string
-FileSpec::GetPath (bool denormalize) const
+FileSpec::GetPath(bool denormalize) const
{
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);
-
+ GetPath(result, denormalize);
return std::string(result.begin(), result.end());
}
+const char *
+FileSpec::GetCString(bool denormalize) const
+{
+ return ConstString{GetPath(denormalize)}.AsCString(NULL);
+}
+
+void
+FileSpec::GetPath(llvm::SmallVectorImpl<char> &path, bool denormalize) const
+{
+ path.append(m_directory.GetStringRef().begin(), m_directory.GetStringRef().end());
+ if (m_directory)
+ path.insert(path.end(), '/');
+ path.append(m_filename.GetStringRef().begin(), m_filename.GetStringRef().end());
+ Normalize(path, m_syntax);
+ if (path.size() > 1 && path.back() == '/') path.pop_back();
+ if (denormalize && !path.empty())
+ Denormalize(path, m_syntax);
+}
+
ConstString
FileSpec::GetFileNameExtension () const
{
@@ -852,6 +939,15 @@ FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const
return data_sp;
}
+DataBufferSP
+FileSpec::MemoryMapFileContentsIfLocal(off_t file_offset, size_t file_size) const
+{
+ if (FileSystem::IsLocal(*this))
+ return MemoryMapFileContents(file_offset, file_size);
+ else
+ return ReadFileContents(file_offset, file_size, NULL);
+}
+
//------------------------------------------------------------------
// Return the size in bytes that this object takes in memory. This
@@ -974,15 +1070,7 @@ FileSpec::ReadFileLines (STLStringArray &lines)
}
FileSpec::EnumerateDirectoryResult
-FileSpec::EnumerateDirectory
-(
- const char *dir_path,
- bool find_directories,
- bool find_files,
- bool find_other,
- EnumerateDirectoryCallbackType callback,
- void *callback_baton
-)
+FileSpec::ForEachItemInDirectory (const char *dir_path, DirectoryCallback const &callback)
{
if (dir_path && dir_path[0])
{
@@ -1000,7 +1088,6 @@ FileSpec::EnumerateDirectory
do
{
- bool call_callback = false;
FileSpec::FileType file_type = eFileTypeUnknown;
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
@@ -1013,31 +1100,27 @@ FileSpec::EnumerateDirectory
continue;
file_type = eFileTypeDirectory;
- call_callback = find_directories;
}
else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE)
{
file_type = eFileTypeOther;
- call_callback = find_other;
}
else
{
file_type = eFileTypeRegular;
- call_callback = find_files;
}
- if (call_callback)
+
+ char child_path[MAX_PATH];
+ const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s\\%s", dir_path, ffd.cFileName);
+ if (child_path_len < (int)(sizeof(child_path) - 1))
{
- char child_path[MAX_PATH];
- const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s\\%s", dir_path, ffd.cFileName);
- if (child_path_len < (int)(sizeof(child_path) - 1))
- {
- // Don't resolve the file type or path
- FileSpec child_path_spec (child_path, false);
+ // Don't resolve the file type or path
+ FileSpec child_path_spec (child_path, false);
- EnumerateDirectoryResult result = callback (callback_baton, file_type, child_path_spec);
+ EnumerateDirectoryResult result = callback (file_type, child_path_spec);
- switch (result)
- {
+ switch (result)
+ {
case eEnumerateDirectoryResultNext:
// Enumerate next entry in the current directory. We just
// exit this switch and will continue enumerating the
@@ -1045,27 +1128,21 @@ FileSpec::EnumerateDirectory
break;
case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not
- if (FileSpec::EnumerateDirectory(child_path,
- find_directories,
- find_files,
- find_other,
- callback,
- callback_baton) == eEnumerateDirectoryResultQuit)
+ if (FileSpec::ForEachItemInDirectory(child_path, callback) == eEnumerateDirectoryResultQuit)
{
- // The subdirectory returned Quit, which means to
+ // The subdirectory returned Quit, which means to
// stop all directory enumerations at all levels.
return eEnumerateDirectoryResultQuit;
}
break;
case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level.
- // Exit from this directory level and tell parent to
+ // Exit from this directory level and tell parent to
// keep enumerating.
return eEnumerateDirectoryResultNext;
case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level
return eEnumerateDirectoryResultQuit;
- }
}
}
} while (FindNextFile(hFind, &ffd) != 0);
@@ -1098,80 +1175,71 @@ FileSpec::EnumerateDirectory
if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
continue;
}
-
- bool call_callback = false;
+
FileSpec::FileType file_type = eFileTypeUnknown;
switch (dp->d_type)
{
- default:
- case DT_UNKNOWN: file_type = eFileTypeUnknown; call_callback = true; break;
- case DT_FIFO: file_type = eFileTypePipe; call_callback = find_other; break;
- case DT_CHR: file_type = eFileTypeOther; call_callback = find_other; break;
- case DT_DIR: file_type = eFileTypeDirectory; call_callback = find_directories; break;
- case DT_BLK: file_type = eFileTypeOther; call_callback = find_other; break;
- case DT_REG: file_type = eFileTypeRegular; call_callback = find_files; break;
- case DT_LNK: file_type = eFileTypeSymbolicLink; call_callback = find_other; break;
- case DT_SOCK: file_type = eFileTypeSocket; call_callback = find_other; break;
+ default:
+ case DT_UNKNOWN: file_type = eFileTypeUnknown; break;
+ case DT_FIFO: file_type = eFileTypePipe; break;
+ case DT_CHR: file_type = eFileTypeOther; break;
+ case DT_DIR: file_type = eFileTypeDirectory; break;
+ case DT_BLK: file_type = eFileTypeOther; break;
+ case DT_REG: file_type = eFileTypeRegular; break;
+ case DT_LNK: file_type = eFileTypeSymbolicLink; break;
+ case DT_SOCK: file_type = eFileTypeSocket; break;
#if !defined(__OpenBSD__)
- case DT_WHT: file_type = eFileTypeOther; call_callback = find_other; break;
+ case DT_WHT: file_type = eFileTypeOther; break;
#endif
}
- if (call_callback)
+ char child_path[PATH_MAX];
+
+ // Don't make paths with "/foo//bar", that just confuses everybody.
+ int child_path_len;
+ if (dir_path_last_char == '/')
+ child_path_len = ::snprintf (child_path, sizeof(child_path), "%s%s", dir_path, dp->d_name);
+ else
+ child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name);
+
+ if (child_path_len < (int)(sizeof(child_path) - 1))
{
- char child_path[PATH_MAX];
+ // Don't resolve the file type or path
+ FileSpec child_path_spec (child_path, false);
- // Don't make paths with "/foo//bar", that just confuses everybody.
- int child_path_len;
- if (dir_path_last_char == '/')
- child_path_len = ::snprintf (child_path, sizeof(child_path), "%s%s", dir_path, dp->d_name);
- else
- child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name);
+ EnumerateDirectoryResult result = callback (file_type, child_path_spec);
- if (child_path_len < (int)(sizeof(child_path) - 1))
+ switch (result)
{
- // Don't resolve the file type or path
- FileSpec child_path_spec (child_path, false);
-
- EnumerateDirectoryResult result = callback (callback_baton, file_type, child_path_spec);
-
- switch (result)
- {
- case eEnumerateDirectoryResultNext:
+ case eEnumerateDirectoryResultNext:
// Enumerate next entry in the current directory. We just
// exit this switch and will continue enumerating the
// current directory as we currently are...
break;
case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not
- if (FileSpec::EnumerateDirectory (child_path,
- find_directories,
- find_files,
- find_other,
- callback,
- callback_baton) == eEnumerateDirectoryResultQuit)
+ if (FileSpec::ForEachItemInDirectory (child_path, callback) == eEnumerateDirectoryResultQuit)
{
- // The subdirectory returned Quit, which means to
+ // The subdirectory returned Quit, which means to
// stop all directory enumerations at all levels.
if (buf)
free (buf);
return eEnumerateDirectoryResultQuit;
}
break;
-
+
case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level.
- // Exit from this directory level and tell parent to
+ // Exit from this directory level and tell parent to
// keep enumerating.
if (buf)
free (buf);
return eEnumerateDirectoryResultNext;
-
+
case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level
if (buf)
free (buf);
return eEnumerateDirectoryResultQuit;
- }
}
}
}
@@ -1187,6 +1255,39 @@ FileSpec::EnumerateDirectory
return eEnumerateDirectoryResultNext;
}
+FileSpec::EnumerateDirectoryResult
+FileSpec::EnumerateDirectory
+(
+ const char *dir_path,
+ bool find_directories,
+ bool find_files,
+ bool find_other,
+ EnumerateDirectoryCallbackType callback,
+ void *callback_baton
+)
+{
+ return ForEachItemInDirectory(dir_path,
+ [&find_directories, &find_files, &find_other, &callback, &callback_baton]
+ (FileType file_type, const FileSpec &file_spec) {
+ switch (file_type)
+ {
+ case FileType::eFileTypeDirectory:
+ if (find_directories)
+ return callback(callback_baton, file_type, file_spec);
+ break;
+ case FileType::eFileTypeRegular:
+ if (find_files)
+ return callback(callback_baton, file_type, file_spec);
+ break;
+ default:
+ if (find_other)
+ return callback(callback_baton, file_type, file_spec);
+ break;
+ }
+ return eEnumerateDirectoryResultNext;
+ });
+}
+
FileSpec
FileSpec::CopyByAppendingPathComponent (const char *new_path) const
{
@@ -1266,25 +1367,70 @@ FileSpec::GetLastPathComponent () const
}
void
-FileSpec::AppendPathComponent (const char *new_path)
+FileSpec::PrependPathComponent(const char *new_path)
{
+ if (!new_path) return;
const bool resolve = false;
if (m_filename.IsEmpty() && m_directory.IsEmpty())
{
- SetFile(new_path,resolve);
+ SetFile(new_path, resolve);
return;
}
StreamString stream;
if (m_filename.IsEmpty())
- stream.Printf("%s/%s",m_directory.GetCString(),new_path);
+ stream.Printf("%s/%s", new_path, m_directory.GetCString());
else if (m_directory.IsEmpty())
- stream.Printf("%s/%s",m_filename.GetCString(),new_path);
+ stream.Printf("%s/%s", new_path, m_filename.GetCString());
else
- stream.Printf("%s/%s/%s",m_directory.GetCString(), m_filename.GetCString(),new_path);
+ stream.Printf("%s/%s/%s", new_path, m_directory.GetCString(), m_filename.GetCString());
SetFile(stream.GetData(), resolve);
}
void
+FileSpec::PrependPathComponent(const std::string &new_path)
+{
+ return PrependPathComponent(new_path.c_str());
+}
+
+void
+FileSpec::PrependPathComponent(const FileSpec &new_path)
+{
+ return PrependPathComponent(new_path.GetPath(false));
+}
+
+void
+FileSpec::AppendPathComponent(const char *new_path)
+{
+ if (!new_path) return;
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ {
+ SetFile(new_path, resolve);
+ return;
+ }
+ StreamString stream;
+ if (m_filename.IsEmpty())
+ stream.Printf("%s/%s", m_directory.GetCString(), new_path);
+ else if (m_directory.IsEmpty())
+ stream.Printf("%s/%s", m_filename.GetCString(), new_path);
+ else
+ stream.Printf("%s/%s/%s", m_directory.GetCString(), m_filename.GetCString(), new_path);
+ SetFile(stream.GetData(), resolve);
+}
+
+void
+FileSpec::AppendPathComponent(const std::string &new_path)
+{
+ return AppendPathComponent(new_path.c_str());
+}
+
+void
+FileSpec::AppendPathComponent(const FileSpec &new_path)
+{
+ return AppendPathComponent(new_path.GetPath(false));
+}
+
+void
FileSpec::RemoveLastPathComponent ()
{
const bool resolve = false;
@@ -1343,22 +1489,14 @@ FileSpec::IsSourceImplementationFile () const
}
bool
-FileSpec::IsRelativeToCurrentWorkingDirectory () const
+FileSpec::IsRelative() const
{
const char *dir = m_directory.GetCString();
llvm::StringRef directory(dir ? dir : "");
if (directory.size() > 0)
{
- if (m_syntax == ePathSyntaxWindows)
- {
- if (directory.size() >= 2 && directory[1] == ':')
- return false;
- if (directory[0] == '/')
- return false;
- return true;
- }
- else
+ if (PathSyntaxIsPosix(m_syntax))
{
// If the path doesn't start with '/' or '~', return true
switch (directory[0])
@@ -1370,6 +1508,14 @@ FileSpec::IsRelativeToCurrentWorkingDirectory () const
return true;
}
}
+ else
+ {
+ if (directory.size() >= 2 && directory[1] == ':')
+ return false;
+ if (directory[0] == '/')
+ return false;
+ return true;
+ }
}
else if (m_filename)
{
@@ -1378,3 +1524,9 @@ FileSpec::IsRelativeToCurrentWorkingDirectory () const
}
return false;
}
+
+bool
+FileSpec::IsAbsolute() const
+{
+ return !FileSpec::IsRelative();
+}
diff --git a/source/Host/common/FileSystem.cpp b/source/Host/common/FileSystem.cpp
new file mode 100644
index 000000000000..5a5dbc79fe11
--- /dev/null
+++ b/source/Host/common/FileSystem.cpp
@@ -0,0 +1,103 @@
+//===-- 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"
+
+#include "llvm/Support/MD5.h"
+
+#include <algorithm>
+#include <fstream>
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+bool
+CalcMD5(const FileSpec &file_spec, uint64_t offset, uint64_t length, llvm::MD5::MD5Result &md5_result)
+{
+ llvm::MD5 md5_hash;
+ std::ifstream file(file_spec.GetPath(), std::ios::binary);
+ if (!file.is_open())
+ return false;
+
+ if (offset > 0)
+ file.seekg(offset, file.beg);
+
+ std::vector<char> read_buf(4096);
+ uint64_t total_read_bytes = 0;
+ while (!file.eof())
+ {
+ const uint64_t to_read = (length > 0) ?
+ std::min(static_cast<uint64_t>(read_buf.size()), length - total_read_bytes) :
+ read_buf.size();
+ if (to_read == 0)
+ break;
+
+ file.read(&read_buf[0], to_read);
+ const auto read_bytes = file.gcount();
+ if (read_bytes == 0)
+ break;
+
+ md5_hash.update(llvm::StringRef(&read_buf[0], read_bytes));
+ total_read_bytes += read_bytes;
+ }
+
+ md5_hash.final(md5_result);
+ return true;
+}
+
+} // namespace
+
+bool
+FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high)
+{
+ return CalculateMD5(file_spec, 0, 0, low, high);
+}
+
+bool
+FileSystem::CalculateMD5(const FileSpec &file_spec,
+ uint64_t offset,
+ uint64_t length,
+ uint64_t &low,
+ uint64_t &high)
+{
+ llvm::MD5::MD5Result md5_result;
+ if (!CalcMD5(file_spec, offset, length, md5_result))
+ return false;
+
+ const auto uint64_res = reinterpret_cast<const uint64_t*>(md5_result);
+ high = uint64_res[0];
+ low = uint64_res[1];
+
+ return true;
+}
+
+bool
+FileSystem::CalculateMD5AsString(const FileSpec &file_spec, std::string& digest_str)
+{
+ return CalculateMD5AsString(file_spec, 0, 0, digest_str);
+}
+
+bool
+FileSystem::CalculateMD5AsString(const FileSpec &file_spec,
+ uint64_t offset,
+ uint64_t length,
+ std::string& digest_str)
+{
+ llvm::MD5::MD5Result md5_result;
+ if (!CalcMD5(file_spec, offset, length, md5_result))
+ return false;
+
+ llvm::SmallString<32> result_str;
+ llvm::MD5::stringifyResult(md5_result, result_str);
+ digest_str = result_str.c_str();
+ return true;
+}
diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp
index 30f5c8683060..20d6355e6195 100644
--- a/source/Host/common/Host.cpp
+++ b/source/Host/common/Host.cpp
@@ -64,6 +64,8 @@
#if defined(_WIN32)
#include "lldb/Host/windows/ProcessLauncherWindows.h"
+#elif defined(__ANDROID__) || defined(__ANDROID_NDK__)
+#include "lldb/Host/android/ProcessLauncherAndroid.h"
#else
#include "lldb/Host/posix/ProcessLauncherPosix.h"
#endif
@@ -111,7 +113,7 @@ Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, vo
return ThreadLauncher::LaunchThread(thread_name, MonitorChildProcessThreadFunction, info_ptr, NULL);
}
-#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
+#ifndef __linux__
//------------------------------------------------------------------
// Scoped class that will disable thread canceling when it is
// constructed, and exception safely restore the previous value it
@@ -138,7 +140,32 @@ public:
private:
int m_old_state; // Save the old cancelability state.
};
-#endif // __ANDROID_NDK__
+#endif // __linux__
+
+#ifdef __linux__
+static thread_local volatile sig_atomic_t g_usr1_called;
+
+static void
+SigUsr1Handler (int)
+{
+ g_usr1_called = 1;
+}
+#endif // __linux__
+
+static bool
+CheckForMonitorCancellation()
+{
+#ifdef __linux__
+ if (g_usr1_called)
+ {
+ g_usr1_called = 0;
+ return true;
+ }
+#else
+ ::pthread_testcancel ();
+#endif
+ return false;
+}
static thread_result_t
MonitorChildProcessThreadFunction (void *arg)
@@ -165,21 +192,29 @@ MonitorChildProcessThreadFunction (void *arg)
#endif
const int options = __WALL;
+#ifdef __linux__
+ // This signal is only used to interrupt the thread from waitpid
+ struct sigaction sigUsr1Action;
+ memset(&sigUsr1Action, 0, sizeof(sigUsr1Action));
+ sigUsr1Action.sa_handler = SigUsr1Handler;
+ ::sigaction(SIGUSR1, &sigUsr1Action, nullptr);
+#endif // __linux__
+
while (1)
{
log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
if (log)
log->Printf("%s ::waitpid (pid = %" PRIi32 ", &status, options = %i)...", function, pid, options);
- // Wait for all child processes
-#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
- ::pthread_testcancel ();
-#endif
+ if (CheckForMonitorCancellation ())
+ break;
+
// Get signals from all children with same process group of pid
const ::pid_t wait_pid = ::waitpid (pid, &status, options);
-#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
- ::pthread_testcancel ();
-#endif
+
+ if (CheckForMonitorCancellation ())
+ break;
+
if (wait_pid == -1)
{
if (errno == EINTR)
@@ -224,7 +259,7 @@ MonitorChildProcessThreadFunction (void *arg)
// Scope for pthread_cancel_disabler
{
-#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
+#ifndef __linux__
ScopedPThreadCancelDisabler pthread_cancel_disabler;
#endif
@@ -388,28 +423,6 @@ Host::GetSignalAsCString (int signo)
#endif
-void
-Host::WillTerminate ()
-{
-}
-
-#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined (__linux__) // see macosx/Host.mm
-
-void
-Host::Backtrace (Stream &strm, uint32_t max_frames)
-{
- // TODO: Is there a way to backtrace the current process on other systems?
-}
-
-size_t
-Host::GetEnvironment (StringList &env)
-{
- // TODO: Is there a way to the host environment for this process on other systems?
- return 0;
-}
-
-#endif // #if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined (__linux__)
-
#ifndef _WIN32
lldb::thread_key_t
@@ -463,8 +476,6 @@ Host::GetModuleFileSpecForHostAddress (const void *host_addr)
if (info.dli_fname)
module_filespec.SetFile(info.dli_fname, true);
}
-#else
- assert(false && "dladdr() not supported on Android");
#endif
return module_filespec;
}
@@ -522,13 +533,25 @@ MonitorShellCommand (void *callback_baton,
}
Error
-Host::RunShellCommand (const char *command,
- const char *working_dir,
- int *status_ptr,
- int *signo_ptr,
- std::string *command_output_ptr,
- uint32_t timeout_sec,
- bool run_in_default_shell)
+Host::RunShellCommand(const char *command,
+ const FileSpec &working_dir,
+ int *status_ptr,
+ int *signo_ptr,
+ std::string *command_output_ptr,
+ uint32_t timeout_sec,
+ bool run_in_default_shell)
+{
+ return RunShellCommand(Args(command), working_dir, status_ptr, signo_ptr, command_output_ptr, timeout_sec, run_in_default_shell);
+}
+
+Error
+Host::RunShellCommand(const Args &args,
+ const FileSpec &working_dir,
+ int *status_ptr,
+ int *signo_ptr,
+ std::string *command_output_ptr,
+ uint32_t timeout_sec,
+ bool run_in_default_shell)
{
Error error;
ProcessLaunchInfo launch_info;
@@ -537,10 +560,10 @@ Host::RunShellCommand (const char *command,
{
// Run the command in a shell
launch_info.SetShell(HostInfo::GetDefaultShell());
- launch_info.GetArguments().AppendArgument(command);
+ launch_info.GetArguments().AppendArguments(args);
const bool localhost = true;
const bool will_debug = false;
- const bool first_arg_is_full_shell_command = true;
+ const bool first_arg_is_full_shell_command = false;
launch_info.ConvertArgumentsForLaunchingInShell (error,
localhost,
will_debug,
@@ -550,7 +573,6 @@ Host::RunShellCommand (const char *command,
else
{
// No shell, just run it
- Args args (command);
const bool first_arg_is_executable = true;
launch_info.SetArguments(args, first_arg_is_executable);
}
@@ -558,7 +580,7 @@ Host::RunShellCommand (const char *command,
if (working_dir)
launch_info.SetWorkingDirectory(working_dir);
llvm::SmallString<PATH_MAX> output_file_path;
-
+
if (command_output_ptr)
{
// Create a temporary file to get the stdout/stderr and redirect the
@@ -575,11 +597,13 @@ Host::RunShellCommand (const char *command,
llvm::sys::fs::createTemporaryFile("lldb-shell-output.%%%%%%", "", output_file_path);
}
}
-
+
+ FileSpec output_file_spec{output_file_path.c_str(), false};
+
launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false);
- if (!output_file_path.empty())
+ if (output_file_spec)
{
- launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_path.c_str(), false, true);
+ launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_spec, false, true);
launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO);
}
else
@@ -596,10 +620,10 @@ Host::RunShellCommand (const char *command,
error = LaunchProcess (launch_info);
const lldb::pid_t pid = launch_info.GetProcessID();
-
+
if (error.Success() && pid == LLDB_INVALID_PROCESS_ID)
error.SetErrorString("failed to get process ID");
-
+
if (error.Success())
{
// The process successfully launched, so we can defer ownership of
@@ -618,7 +642,7 @@ Host::RunShellCommand (const char *command,
if (timed_out)
{
error.SetErrorString("timed out waiting for shell command to complete");
-
+
// Kill the process since it didn't complete within the timeout specified
Kill (pid, SIGKILL);
// Wait for the monitor callback to get the message
@@ -631,15 +655,14 @@ Host::RunShellCommand (const char *command,
{
if (status_ptr)
*status_ptr = shell_info->status;
-
+
if (signo_ptr)
*signo_ptr = shell_info->signo;
-
+
if (command_output_ptr)
{
command_output_ptr->clear();
- FileSpec file_spec(output_file_path.c_str(), File::eOpenOptionRead);
- uint64_t file_size = file_spec.GetByteSize();
+ uint64_t file_size = output_file_spec.GetByteSize();
if (file_size > 0)
{
if (file_size > command_output_ptr->max_size())
@@ -648,8 +671,10 @@ Host::RunShellCommand (const char *command,
}
else
{
- command_output_ptr->resize(file_size);
- file_spec.ReadFileContents(0, &((*command_output_ptr)[0]), command_output_ptr->size(), &error);
+ std::vector<char> command_output(file_size);
+ output_file_spec.ReadFileContents(0, command_output.data(), file_size, &error);
+ if (error.Success())
+ command_output_ptr->assign(command_output.data(), file_size);
}
}
}
@@ -657,27 +682,25 @@ Host::RunShellCommand (const char *command,
shell_info->can_delete.SetValue(true, eBroadcastAlways);
}
- FileSpec output_file_spec(output_file_path.c_str(), false);
if (FileSystem::GetFileExists(output_file_spec))
- FileSystem::Unlink(output_file_path.c_str());
+ FileSystem::Unlink(output_file_spec);
// Handshake with the monitor thread, or just let it know in advance that
// it can delete "shell_info" in case we timed out and were not able to kill
// the process...
return error;
}
-
// LaunchProcessPosixSpawn for Apple, Linux, FreeBSD and other GLIBC
// systems
#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__)
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
// this method needs to be visible to macosx/Host.cpp and
// common/Host.cpp.
short
Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info)
{
-#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
#if defined (__APPLE__)
@@ -720,17 +743,12 @@ Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info)
#endif
#endif // #if defined (__APPLE__)
return flags;
-#else
- assert(false && "Host::GetPosixspawnFlags() not supported on Android");
- return 0;
-#endif
}
Error
Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
{
Error error;
-#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
posix_spawnattr_t attr;
@@ -816,16 +834,18 @@ Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &lau
current_dir[0] = '\0';
#endif
- const char *working_dir = launch_info.GetWorkingDirectory();
+ FileSpec working_dir{launch_info.GetWorkingDirectory()};
if (working_dir)
{
#if defined (__APPLE__)
// Set the working directory on this thread only
- if (__pthread_chdir (working_dir) < 0) {
+ if (__pthread_chdir(working_dir.GetCString()) < 0) {
if (errno == ENOENT) {
- error.SetErrorStringWithFormat("No such file or directory: %s", working_dir);
+ error.SetErrorStringWithFormat("No such file or directory: %s",
+ working_dir.GetCString());
} else if (errno == ENOTDIR) {
- error.SetErrorStringWithFormat("Path doesn't name a directory: %s", working_dir);
+ error.SetErrorStringWithFormat("Path doesn't name a directory: %s",
+ working_dir.GetCString());
} else {
error.SetErrorStringWithFormat("An unknown error occurred when changing directory for process execution.");
}
@@ -839,10 +859,11 @@ Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &lau
return error;
}
- if (::chdir(working_dir) == -1)
+ if (::chdir(working_dir.GetCString()) == -1)
{
error.SetError(errno, eErrorTypePOSIX);
- error.LogIfError(log, "unable to change working directory to %s", working_dir);
+ error.LogIfError(log, "unable to change working directory to %s",
+ working_dir.GetCString());
return error;
}
#endif
@@ -920,9 +941,6 @@ Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &lau
}
#endif
}
-#else
- error.SetErrorString("Host::LaunchProcessPosixSpawn() not supported on Android");
-#endif
return error;
}
@@ -930,7 +948,6 @@ Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &lau
bool
Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log *log, Error &error)
{
-#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
if (info == NULL)
return false;
@@ -993,12 +1010,9 @@ Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log *
break;
}
return error.Success();
-#else
- error.SetErrorString("Host::AddPosixSpawnFileAction() not supported on Android");
- return false;
-#endif
}
-#endif // LaunchProcedssPosixSpawn: Apple, Linux, FreeBSD and other GLIBC systems
+#endif // !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
+#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__)
#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || defined(__NetBSD__) || defined(_WIN32)
// The functions below implement process launching via posix_spawn() for Linux,
@@ -1010,6 +1024,8 @@ Host::LaunchProcess (ProcessLaunchInfo &launch_info)
std::unique_ptr<ProcessLauncher> delegate_launcher;
#if defined(_WIN32)
delegate_launcher.reset(new ProcessLauncherWindows());
+#elif defined(__ANDROID__) || defined(__ANDROID_NDK__)
+ delegate_launcher.reset(new ProcessLauncherAndroid());
#else
delegate_launcher.reset(new ProcessLauncherPosix());
#endif
@@ -1054,7 +1070,7 @@ Host::SetCrashDescription (const char *description)
#endif
-#if !defined (__linux__) && !defined (__FreeBSD__) && !defined (__NetBSD__)
+#if !defined (__linux__) && !defined (__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined (__NetBSD__)
const lldb_private::UnixSignalsSP&
Host::GetUnixSignals ()
diff --git a/source/Host/common/HostInfoBase.cpp b/source/Host/common/HostInfoBase.cpp
index 9816c1ebf080..e969e33190eb 100644
--- a/source/Host/common/HostInfoBase.cpp
+++ b/source/Host/common/HostInfoBase.cpp
@@ -40,7 +40,7 @@ namespace
// 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);
+ FileSystem::DeleteDirectory(tmpdir_file_spec, true);
}
//----------------------------------------------------------------------
@@ -68,7 +68,8 @@ namespace
FileSpec m_lldb_clang_resource_dir;
FileSpec m_lldb_system_plugin_dir;
FileSpec m_lldb_user_plugin_dir;
- FileSpec m_lldb_tmp_dir;
+ FileSpec m_lldb_process_tmp_dir;
+ FileSpec m_lldb_global_tmp_dir;
};
HostInfoBaseFields *g_fields = nullptr;
@@ -263,13 +264,27 @@ HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec)
static std::once_flag g_once_flag;
static bool success = false;
std::call_once(g_once_flag, []() {
- success = HostInfo::ComputeTempFileDirectory (g_fields->m_lldb_tmp_dir);
+ success = HostInfo::ComputeProcessTempFileDirectory (g_fields->m_lldb_process_tmp_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
- log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_tmp_dir.GetPath().c_str());
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_process_tmp_dir.GetPath().c_str());
});
if (success)
- result = &g_fields->m_lldb_tmp_dir;
+ result = &g_fields->m_lldb_process_tmp_dir;
+ }
+ break;
+ case lldb::ePathTypeGlobalLLDBTempSystemDir:
+ {
+ static std::once_flag g_once_flag;
+ static bool success = false;
+ std::call_once(g_once_flag, []() {
+ success = HostInfo::ComputeGlobalTempFileDirectory (g_fields->m_lldb_global_tmp_dir);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeGlobalLLDBTempSystemDir) => '%s'", g_fields->m_lldb_global_tmp_dir.GetPath().c_str());
+ });
+ if (success)
+ result = &g_fields->m_lldb_global_tmp_dir;
}
break;
}
@@ -305,35 +320,57 @@ HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec)
}
bool
-HostInfoBase::ComputeTempFileDirectory(FileSpec &file_spec)
+HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec)
+{
+ FileSpec temp_file_spec;
+ if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
+ return false;
+
+ std::string pid_str{std::to_string(Host::GetCurrentProcessID())};
+ temp_file_spec.AppendPathComponent(pid_str);
+ if (!FileSystem::MakeDirectory(temp_file_spec, 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().SetCString(temp_file_spec.GetCString());
+ return true;
+}
+
+bool
+HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec)
{
+ file_spec.Clear();
+
const char *tmpdir_cstr = getenv("TMPDIR");
- if (tmpdir_cstr == NULL)
+ if (tmpdir_cstr == nullptr)
{
tmpdir_cstr = getenv("TMP");
- if (tmpdir_cstr == NULL)
+ if (tmpdir_cstr == nullptr)
tmpdir_cstr = getenv("TEMP");
}
if (!tmpdir_cstr)
return false;
- FileSpec temp_file_spec(tmpdir_cstr, false);
- temp_file_spec.AppendPathComponent("lldb");
- if (!FileSystem::MakeDirectory(temp_file_spec.GetPath().c_str(), eFilePermissionsDirectoryDefault).Success())
+ file_spec = FileSpec(tmpdir_cstr, false);
+ return true;
+}
+
+bool
+HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec)
+{
+ file_spec.Clear();
+
+ FileSpec temp_file_spec;
+ if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
return false;
- std::string pid_str;
- llvm::raw_string_ostream pid_stream(pid_str);
- pid_stream << Host::GetCurrentProcessID();
- temp_file_spec.AppendPathComponent(pid_stream.str().c_str());
- std::string final_path = temp_file_spec.GetPath();
- if (!FileSystem::MakeDirectory(final_path.c_str(), eFilePermissionsDirectoryDefault).Success())
+ temp_file_spec.AppendPathComponent("lldb");
+ if (!FileSystem::MakeDirectory(temp_file_spec, 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(final_path.c_str(), final_path.size());
+ file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
return true;
}
@@ -367,7 +404,7 @@ HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec)
void
HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64)
{
- llvm::Triple triple(llvm::sys::getDefaultTargetTriple());
+ llvm::Triple triple(llvm::sys::getProcessTriple());
arch_32.Clear();
arch_64.Clear();
@@ -386,6 +423,7 @@ HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_6
case llvm::Triple::aarch64:
case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
case llvm::Triple::sparcv9:
arch_64.SetTriple(triple);
break;
diff --git a/source/Host/common/LockFileBase.cpp b/source/Host/common/LockFileBase.cpp
new file mode 100644
index 000000000000..f74694561184
--- /dev/null
+++ b/source/Host/common/LockFileBase.cpp
@@ -0,0 +1,124 @@
+//===-- LockFileBase.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/LockFileBase.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+
+Error
+AlreadyLocked ()
+{
+ return Error ("Already locked");
+}
+
+Error
+NotLocked ()
+{
+ return Error ("Not locked");
+}
+
+}
+
+LockFileBase::LockFileBase (int fd) :
+ m_fd (fd),
+ m_locked (false),
+ m_start (0),
+ m_len (0)
+{
+
+}
+
+bool
+LockFileBase::IsLocked () const
+{
+ return m_locked;
+}
+
+Error
+LockFileBase::WriteLock (const uint64_t start, const uint64_t len)
+{
+ return DoLock ([&] (const uint64_t start, const uint64_t len)
+ {
+ return DoWriteLock (start, len);
+ }, start, len);
+}
+
+Error
+LockFileBase::TryWriteLock (const uint64_t start, const uint64_t len)
+{
+ return DoLock ([&] (const uint64_t start, const uint64_t len)
+ {
+ return DoTryWriteLock (start, len);
+ }, start, len);
+}
+
+Error
+LockFileBase::ReadLock (const uint64_t start, const uint64_t len)
+{
+ return DoLock ([&] (const uint64_t start, const uint64_t len)
+ {
+ return DoReadLock (start, len);
+ }, start, len);
+}
+
+Error
+LockFileBase::TryReadLock (const uint64_t start, const uint64_t len)
+{
+ return DoLock ([&] (const uint64_t start, const uint64_t len)
+ {
+ return DoTryReadLock (start, len);
+ }, start, len);
+
+}
+
+Error
+LockFileBase::Unlock ()
+{
+ if (!IsLocked ())
+ return NotLocked ();
+
+ const auto error = DoUnlock ();
+ if (error.Success ())
+ {
+ m_locked = false;
+ m_start = 0;
+ m_len = 0;
+ }
+ return error;
+}
+
+bool
+LockFileBase::IsValidFile () const
+{
+ return m_fd != -1;
+}
+
+Error
+LockFileBase::DoLock (const Locker &locker, const uint64_t start, const uint64_t len)
+{
+ if (!IsValidFile ())
+ return Error("File is invalid");
+
+ if (IsLocked ())
+ return AlreadyLocked ();
+
+ const auto error = locker (start, len);
+ if (error.Success ())
+ {
+ m_locked = true;
+ m_start = start;
+ m_len = len;
+ }
+
+ return error;
+}
diff --git a/source/Host/common/NativeBreakpointList.cpp b/source/Host/common/NativeBreakpointList.cpp
index 94d0b3756da4..52b9baf5f537 100644
--- a/source/Host/common/NativeBreakpointList.cpp
+++ b/source/Host/common/NativeBreakpointList.cpp
@@ -12,6 +12,7 @@
#include "lldb/Core/Log.h"
#include "lldb/Host/common/NativeBreakpoint.h"
+#include "lldb/Host/common/SoftwareBreakpoint.h"
using namespace lldb;
using namespace lldb_private;
@@ -197,3 +198,24 @@ NativeBreakpointList::GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &brea
return Error ();
}
+Error
+NativeBreakpointList::RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf, size_t size) const
+{
+ for (const auto &map : m_breakpoints)
+ {
+ lldb::addr_t bp_addr = map.first;
+ // Breapoint not in range, ignore
+ if (bp_addr < addr || addr + size <= bp_addr)
+ continue;
+ const auto &bp_sp = map.second;
+ // Not software breakpoint, ignore
+ if (!bp_sp->IsSoftwareBreakpoint())
+ continue;
+ auto software_bp_sp = std::static_pointer_cast<SoftwareBreakpoint>(bp_sp);
+ auto opcode_addr = static_cast<char *>(buf) + bp_addr - addr;
+ auto saved_opcodes = software_bp_sp->m_saved_opcodes;
+ auto opcode_size = software_bp_sp->m_opcode_size;
+ ::memcpy(opcode_addr, saved_opcodes, opcode_size);
+ }
+ return Error();
+}
diff --git a/source/Host/common/NativeProcessProtocol.cpp b/source/Host/common/NativeProcessProtocol.cpp
index ff7310d2d45a..35003f5d0207 100644
--- a/source/Host/common/NativeProcessProtocol.cpp
+++ b/source/Host/common/NativeProcessProtocol.cpp
@@ -435,3 +435,9 @@ NativeProcessProtocol::DoStopIDBumped (uint32_t /* newBumpId */)
{
// Default implementation does nothing.
}
+
+void
+NativeProcessProtocol::Terminate ()
+{
+ // Default implementation does nothing.
+}
diff --git a/source/Host/common/NativeRegisterContext.cpp b/source/Host/common/NativeRegisterContext.cpp
index 42a9c91a63a0..37040efc4ece 100644
--- a/source/Host/common/NativeRegisterContext.cpp
+++ b/source/Host/common/NativeRegisterContext.cpp
@@ -12,8 +12,6 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/RegisterValue.h"
-#include "lldb/lldb-private-log.h"
-
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
@@ -145,6 +143,12 @@ NativeRegisterContext::GetPC (lldb::addr_t fail_value)
return retval;
}
+lldb::addr_t
+NativeRegisterContext::GetPCfromBreakpointLocation (lldb::addr_t fail_value)
+{
+ return GetPC (fail_value);
+}
+
Error
NativeRegisterContext::SetPC (lldb::addr_t pc)
{
@@ -303,6 +307,33 @@ NativeRegisterContext::ClearAllHardwareWatchpoints ()
return Error ("not implemented");
}
+Error
+NativeRegisterContext::IsWatchpointHit(uint32_t wp_index, bool &is_hit)
+{
+ is_hit = false;
+ return Error ("not implemented");
+}
+
+Error
+NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
+{
+ wp_index = LLDB_INVALID_INDEX32;
+ return Error ("not implemented");
+}
+
+Error
+NativeRegisterContext::IsWatchpointVacant (uint32_t wp_index, bool &is_vacant)
+{
+ is_vacant = false;
+ return Error ("not implemented");
+}
+
+lldb::addr_t
+NativeRegisterContext::GetWatchpointAddress (uint32_t wp_index)
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
bool
NativeRegisterContext::HardwareSingleStep (bool enable)
{
@@ -313,7 +344,7 @@ Error
NativeRegisterContext::ReadRegisterValueFromMemory (
const RegisterInfo *reg_info,
lldb::addr_t src_addr,
- lldb::addr_t src_len,
+ size_t src_len,
RegisterValue &reg_value)
{
Error error;
@@ -346,11 +377,12 @@ NativeRegisterContext::ReadRegisterValueFromMemory (
return error;
}
- const lldb::addr_t dst_len = reg_info->byte_size;
+ const size_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);
+ error.SetErrorStringWithFormat("%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 " bytes)",
+ static_cast<uint64_t>(src_len), reg_info->name, static_cast<uint64_t>(dst_len));
return error;
}
@@ -364,7 +396,7 @@ NativeRegisterContext::ReadRegisterValueFromMemory (
uint8_t src[RegisterValue::kMaxRegisterByteSize];
// Read the memory
- lldb::addr_t bytes_read;
+ size_t bytes_read;
error = process_sp->ReadMemory (src_addr, src, src_len, bytes_read);
if (error.Fail ())
return error;
@@ -373,7 +405,8 @@ NativeRegisterContext::ReadRegisterValueFromMemory (
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);
+ error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes",
+ static_cast<uint64_t>(bytes_read), static_cast<uint64_t>(src_len));
return error;
}
@@ -403,7 +436,7 @@ Error
NativeRegisterContext::WriteRegisterValueToMemory (
const RegisterInfo *reg_info,
lldb::addr_t dst_addr,
- lldb::addr_t dst_len,
+ size_t dst_len,
const RegisterValue &reg_value)
{
@@ -422,7 +455,7 @@ NativeRegisterContext::WriteRegisterValueToMemory (
if (!process_sp->GetByteOrder (byte_order))
return Error ("NativeProcessProtocol::GetByteOrder () failed");
- const lldb::addr_t bytes_copied = reg_value.GetAsMemoryData (
+ const size_t bytes_copied = reg_value.GetAsMemoryData (
reg_info,
dst,
dst_len,
@@ -437,15 +470,16 @@ NativeRegisterContext::WriteRegisterValueToMemory (
}
else
{
- lldb::addr_t bytes_written;
- error = process_sp->WriteMemory (dst_addr, dst, bytes_copied, bytes_written);
+ size_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);
+ error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 " bytes",
+ static_cast<uint64_t>(bytes_written), static_cast<uint64_t>(bytes_copied));
}
}
}
diff --git a/source/Host/common/Socket.cpp b/source/Host/common/Socket.cpp
index b5559fffb45d..f7e93c634a12 100644
--- a/source/Host/common/Socket.cpp
+++ b/source/Host/common/Socket.cpp
@@ -80,6 +80,25 @@ NativeSocket Accept(NativeSocket sockfd, struct sockaddr *addr, socklen_t *addrl
return ::accept (sockfd, addr, addrlen);
#endif
}
+
+void SetLastError(Error &error)
+{
+#if defined(_WIN32)
+ error.SetError(::WSAGetLastError(), lldb::eErrorTypeWin32);
+#else
+ error.SetErrorToErrno();
+#endif
+}
+
+bool IsInterrupted()
+{
+#if defined(_WIN32)
+ return ::WSAGetLastError() == WSAEINTR;
+#else
+ return errno == EINTR;
+#endif
+}
+
}
Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close)
@@ -116,8 +135,7 @@ Error Socket::TcpConnect(llvm::StringRef host_and_port, bool child_processes_inh
sock = CreateSocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, child_processes_inherit);
if (sock == kInvalidSocketValue)
{
- // TODO: On Windows, use WSAGetLastError().
- error.SetErrorToErrno();
+ SetLastError (error);
return error;
}
@@ -143,9 +161,8 @@ Error Socket::TcpConnect(llvm::StringRef host_and_port, bool child_processes_inh
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();
+ SetLastError(error);
else
error.SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str());
@@ -155,8 +172,7 @@ Error Socket::TcpConnect(llvm::StringRef host_and_port, bool child_processes_inh
if (-1 == ::connect (sock, (const struct sockaddr *)&sa, sizeof(sa)))
{
- // TODO: On Windows, use WSAGetLastError()
- error.SetErrorToErrno();
+ SetLastError (error);
return error;
}
@@ -167,7 +183,12 @@ Error Socket::TcpConnect(llvm::StringRef host_and_port, bool child_processes_inh
return error;
}
-Error Socket::TcpListen(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket, Predicate<uint16_t>* predicate)
+Error Socket::TcpListen(
+ llvm::StringRef host_and_port,
+ bool child_processes_inherit,
+ Socket *&socket,
+ Predicate<uint16_t>* predicate,
+ int backlog)
{
std::unique_ptr<Socket> listen_socket;
NativeSocket listen_sock = kInvalidSocketValue;
@@ -179,7 +200,7 @@ Error Socket::TcpListen(llvm::StringRef host_and_port, bool child_processes_inhe
listen_sock = ::CreateSocket (family, socktype, protocol, child_processes_inherit);
if (listen_sock == kInvalidSocketValue)
{
- error.SetErrorToErrno();
+ SetLastError (error);
return error;
}
@@ -204,16 +225,14 @@ Error Socket::TcpListen(llvm::StringRef host_and_port, bool child_processes_inhe
int err = ::bind (listen_sock, anyaddr, anyaddr.GetLength());
if (err == -1)
{
- // TODO: On Windows, use WSAGetLastError()
- error.SetErrorToErrno();
+ SetLastError (error);
return error;
}
- err = ::listen (listen_sock, 1);
+ err = ::listen (listen_sock, backlog);
if (err == -1)
{
- // TODO: On Windows, use WSAGetLastError()
- error.SetErrorToErrno();
+ SetLastError (error);
return error;
}
@@ -284,8 +303,7 @@ Error Socket::BlockingAccept(llvm::StringRef host_and_port, bool child_processes
if (sock == kInvalidSocketValue)
{
- // TODO: On Windows, use WSAGetLastError()
- error.SetErrorToErrno();
+ SetLastError (error);
break;
}
@@ -349,8 +367,7 @@ Error Socket::UdpConnect(llvm::StringRef host_and_port, bool child_processes_inh
if (final_recv_fd == kInvalidSocketValue)
{
// Socket creation failed...
- // TODO: On Windows, use WSAGetLastError().
- error.SetErrorToErrno();
+ SetLastError (error);
}
else
{
@@ -363,8 +380,7 @@ Error Socket::UdpConnect(llvm::StringRef host_and_port, bool child_processes_inh
if (::bind (final_recv_fd, addr, addr.GetLength()) == -1)
{
// Bind failed...
- // TODO: On Windows use WSAGetLastError()
- error.SetErrorToErrno();
+ SetLastError (error);
}
}
@@ -415,8 +431,7 @@ Error Socket::UdpConnect(llvm::StringRef host_and_port, bool child_processes_inh
if (final_send_fd == kInvalidSocketValue)
{
- // TODO: On Windows, use WSAGetLastError().
- error.SetErrorToErrno();
+ SetLastError (error);
return error;
}
@@ -437,7 +452,7 @@ Error Socket::UnixDomainConnect(llvm::StringRef name, bool child_processes_inher
int fd = ::CreateSocket (AF_UNIX, SOCK_STREAM, 0, child_processes_inherit);
if (fd == kInvalidSocketValue)
{
- error.SetErrorToErrno();
+ SetLastError (error);
return error;
}
@@ -452,7 +467,7 @@ Error Socket::UnixDomainConnect(llvm::StringRef name, bool child_processes_inher
if (::connect (fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0)
{
- error.SetErrorToErrno();
+ SetLastError (error);
return error;
}
@@ -476,7 +491,7 @@ Error Socket::UnixDomainAccept(llvm::StringRef name, bool child_processes_inheri
listen_fd = ::CreateSocket (AF_UNIX, SOCK_STREAM, 0, child_processes_inherit);
if (listen_fd == kInvalidSocketValue)
{
- error.SetErrorToErrno();
+ SetLastError (error);
return error;
}
@@ -489,7 +504,7 @@ Error Socket::UnixDomainAccept(llvm::StringRef name, bool child_processes_inheri
saddr_un.sun_len = SUN_LEN (&saddr_un);
#endif
- FileSystem::Unlink(name.data());
+ FileSystem::Unlink(FileSpec{name, true});
bool success = false;
if (::bind (listen_fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0)
{
@@ -506,7 +521,7 @@ Error Socket::UnixDomainAccept(llvm::StringRef name, bool child_processes_inheri
if (!success)
{
- error.SetErrorToErrno();
+ SetLastError (error);
return error;
}
// We are done with the listen port
@@ -580,12 +595,11 @@ Error Socket::Read (void *buf, size_t &num_bytes)
do
{
bytes_received = ::recv (m_socket, static_cast<char *>(buf), num_bytes, 0);
- // TODO: Use WSAGetLastError on windows.
- } while (bytes_received < 0 && errno == EINTR);
+ } while (bytes_received < 0 && IsInterrupted ());
if (bytes_received < 0)
{
- error.SetErrorToErrno();
+ SetLastError (error);
num_bytes = 0;
}
else
@@ -623,13 +637,11 @@ Error Socket::Write (const void *buf, size_t &num_bytes)
}
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);
+ } while (bytes_sent < 0 && IsInterrupted ());
if (bytes_sent < 0)
{
- // TODO: On Windows, use WSAGEtLastError.
- error.SetErrorToErrno();
+ SetLastError (error);
num_bytes = 0;
}
else
@@ -675,8 +687,7 @@ Error Socket::Close()
m_socket = kInvalidSocketValue;
if (!success)
{
- // TODO: On Windows, use WSAGetLastError().
- error.SetErrorToErrno();
+ SetLastError (error);
}
return error;
@@ -699,7 +710,7 @@ int Socket::SetOption(int level, int option_name, int option_value)
uint16_t Socket::GetLocalPortNumber(const NativeSocket& socket)
{
// We bound to port zero, so we need to figure out which port we actually bound to
- if (socket >= 0)
+ if (socket != kInvalidSocketValue)
{
SocketAddress sock_addr;
socklen_t sock_addr_len = sock_addr.GetMaxLength ();
@@ -718,7 +729,7 @@ uint16_t Socket::GetLocalPortNumber() const
std::string Socket::GetLocalIPAddress () const
{
// We bound to port zero, so we need to figure out which port we actually bound to
- if (m_socket >= 0)
+ if (m_socket != kInvalidSocketValue)
{
SocketAddress sock_addr;
socklen_t sock_addr_len = sock_addr.GetMaxLength ();
@@ -730,7 +741,7 @@ std::string Socket::GetLocalIPAddress () const
uint16_t Socket::GetRemotePortNumber () const
{
- if (m_socket >= 0)
+ if (m_socket != kInvalidSocketValue)
{
SocketAddress sock_addr;
socklen_t sock_addr_len = sock_addr.GetMaxLength ();
@@ -743,7 +754,7 @@ uint16_t Socket::GetRemotePortNumber () const
std::string Socket::GetRemoteIPAddress () const
{
// We bound to port zero, so we need to figure out which port we actually bound to
- if (m_socket >= 0)
+ if (m_socket != kInvalidSocketValue)
{
SocketAddress sock_addr;
socklen_t sock_addr_len = sock_addr.GetMaxLength ();
diff --git a/source/Host/common/SocketAddress.cpp b/source/Host/common/SocketAddress.cpp
index fd7fbac952e3..3ab6cfeec4a0 100644
--- a/source/Host/common/SocketAddress.cpp
+++ b/source/Host/common/SocketAddress.cpp
@@ -9,10 +9,13 @@
#include "lldb/Host/SocketAddress.h"
#include <stddef.h>
+#include <stdio.h>
// C Includes
#if !defined(_WIN32)
#include <arpa/inet.h>
+#else
+#include "lldb/Host/windows/win32.h"
#endif
#include <assert.h>
#include <string.h>
@@ -45,8 +48,7 @@ const char* inet_ntop(int af, const void * src,
const char* formatted = inet_ntoa(*static_cast<const in_addr*>(src));
if (formatted && strlen(formatted) < size)
{
- strncpy(dst, formatted, size);
- return dst;
+ return ::strcpy(dst, formatted);
}
}
return nullptr;
@@ -54,15 +56,14 @@ const char* inet_ntop(int af, const void * src,
{
char tmp[INET6_ADDRSTRLEN] = {0};
const uint16_t* src16 = static_cast<const uint16_t*>(src);
- int full_size = _snprintf(tmp, sizeof(tmp),
+ int full_size = ::snprintf(tmp, sizeof(tmp),
"%x:%x:%x:%x:%x:%x:%x:%x",
ntohs(src16[0]), ntohs(src16[1]), ntohs(src16[2]), ntohs(src16[3]),
ntohs(src16[4]), ntohs(src16[5]), ntohs(src16[6]), ntohs(src16[7])
);
if (full_size < static_cast<int>(size))
{
- strncpy(dst,tmp,size);
- return dst;
+ return ::strcpy(dst, tmp);
}
return nullptr;
}
diff --git a/source/Host/common/SoftwareBreakpoint.cpp b/source/Host/common/SoftwareBreakpoint.cpp
index 67f472b88f5c..5a6f78372b3f 100644
--- a/source/Host/common/SoftwareBreakpoint.cpp
+++ b/source/Host/common/SoftwareBreakpoint.cpp
@@ -101,9 +101,9 @@ SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, ll
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;
+ size_t bytes_read = 0;
- Error error = process.ReadMemory(addr, saved_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), bytes_read);
+ Error error = process.ReadMemory(addr, saved_opcode_bytes, bp_opcode_size, bytes_read);
if (error.Fail ())
{
if (log)
@@ -112,11 +112,11 @@ SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, ll
}
// Ensure we read as many bytes as we expected.
- if (bytes_read != static_cast<lldb::addr_t> (bp_opcode_size))
+ if (bytes_read != 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);
+ 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, (uint64_t)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, (uint64_t)bytes_read);
}
// Log what we read.
@@ -125,13 +125,15 @@ SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, ll
int i = 0;
for (const uint8_t *read_byte = saved_opcode_bytes; read_byte < saved_opcode_bytes + bp_opcode_size; ++read_byte)
{
- log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " ovewriting byte index %d (was 0x%x)", __FUNCTION__, addr, i++, static_cast<int> (*read_byte));
+ log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
+ " ovewriting byte index %d (was 0x%hhx)",
+ __FUNCTION__, addr, i++, *read_byte);
}
}
// 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);
+ size_t bytes_written = 0;
+ error = process.WriteMemory(addr, bp_opcode_bytes, bp_opcode_size, bytes_written);
if (error.Fail ())
{
if (log)
@@ -140,17 +142,17 @@ SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, ll
}
// Ensure we wrote as many bytes as we expected.
- if (bytes_written != static_cast<lldb::addr_t> (bp_opcode_size))
+ if (bytes_written != 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);
+ 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, (uint64_t)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);
+ size_t verify_bytes_read = 0;
+ error = process.ReadMemory(addr, verify_bp_opcode_bytes, bp_opcode_size, verify_bytes_read);
if (error.Fail ())
{
if (log)
@@ -159,11 +161,11 @@ SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, ll
}
// Ensure we read as many verification bytes as we expected.
- if (verify_bytes_read != static_cast<lldb::addr_t> (bp_opcode_size))
+ if (verify_bytes_read != 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);
+ 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, (uint64_t)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, (uint64_t)verify_bytes_read);
}
if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0)
@@ -223,26 +225,26 @@ SoftwareBreakpoint::DoDisable ()
assert (m_opcode_size <= sizeof (curr_break_op));
// Read the breakpoint opcode
- lldb::addr_t bytes_read = 0;
+ size_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)))
+ if (error.Success() && bytes_read < 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);
+ error.SetErrorStringWithFormat ("SoftwareBreakpointr::%s addr=0x%" PRIx64 ": tried to read %lu bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)bytes_read);
}
if (error.Success ())
{
bool verify = false;
- // Make sure we have the a breakpoint opcode exists at this address
+ // Make sure the 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;
+ size_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)))
+ if (error.Success() && bytes_written < 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);
+ error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)bytes_written);
}
if (error.Success ())
{
@@ -262,11 +264,11 @@ SoftwareBreakpoint::DoDisable ()
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;
+ size_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)))
+ if (error.Success() && verify_bytes_read < 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);
+ error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to read %lu verification bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)verify_bytes_read);
}
if (error.Success ())
{
@@ -279,7 +281,9 @@ SoftwareBreakpoint::DoDisable ()
int i = 0;
for (const uint8_t *verify_byte = verify_opcode; verify_byte < verify_opcode + m_opcode_size; ++verify_byte)
{
- log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " replaced byte index %d with 0x%x", __FUNCTION__, m_addr, i++, static_cast<int> (*verify_byte));
+ log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
+ " replaced byte index %d with 0x%hhx",
+ __FUNCTION__, m_addr, i++, *verify_byte);
}
log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, m_addr);
}
diff --git a/source/Host/common/Symbols.cpp b/source/Host/common/Symbols.cpp
index 41f465abc836..2b63f46c02e6 100644
--- a/source/Host/common/Symbols.cpp
+++ b/source/Host/common/Symbols.cpp
@@ -18,137 +18,271 @@
#include "lldb/Core/UUID.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/SafeMachO.h"
+
+#include "llvm/Support/FileSystem.h"
+
+// From MacOSX system header "mach/machine.h"
+typedef int cpu_type_t;
+typedef int cpu_subtype_t;
using namespace lldb;
using namespace lldb_private;
+using namespace llvm::MachO;
-#if defined (__linux__) || defined (__FreeBSD__)
+#if defined(__APPLE__)
-FileSpec
-Symbols::LocateExecutableObjectFile (const ModuleSpec &module_spec)
-{
- // FIXME
- return FileSpec();
-}
+// Forward declaration of method defined in source/Host/macosx/Symbols.cpp
+int
+LocateMacOSXFilesUsingDebugSymbols
+(
+ const ModuleSpec &module_spec,
+ FileSpec *out_exec_fspec, // If non-NULL, try and find the executable
+ FileSpec *out_dsym_fspec // If non-NULL try and find the debug symbol file
+);
-FileSpec
-Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec)
-{
- const char *symbol_filename = module_spec.GetSymbolFileSpec().GetFilename().AsCString();
- if (!symbol_filename || !symbol_filename[0])
- return FileSpec();
+#else
- FileSpecList debug_file_search_paths (Target::GetDefaultDebugFileSearchPaths());
-
- // Add module directory.
- const ConstString &file_dir = module_spec.GetFileSpec().GetDirectory();
- debug_file_search_paths.AppendIfUnique (FileSpec(file_dir.AsCString("."), true));
-
- // Add current working directory.
- debug_file_search_paths.AppendIfUnique (FileSpec(".", true));
+int
+LocateMacOSXFilesUsingDebugSymbols
+(
+ const ModuleSpec &module_spec,
+ FileSpec *out_exec_fspec, // If non-NULL, try and find the executable
+ FileSpec *out_dsym_fspec // If non-NULL try and find the debug symbol file
+) {
+ // Cannot find MacOSX files using debug symbols on non MacOSX.
+ return 0;
+}
- // Add /usr/lib/debug directory.
- debug_file_search_paths.AppendIfUnique (FileSpec("/usr/lib/debug", true));
+#endif
- std::string uuid_str;
- const UUID &module_uuid = module_spec.GetUUID();
- if (module_uuid.IsValid())
+static bool
+FileAtPathContainsArchAndUUID (const FileSpec &file_fspec, const ArchSpec *arch, const lldb_private::UUID *uuid)
+{
+ ModuleSpecList module_specs;
+ if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs))
{
- // Some debug files are stored in the .build-id directory like this:
- // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug
- uuid_str = module_uuid.GetAsString("");
- uuid_str.insert (2, 1, '/');
- uuid_str = uuid_str + ".debug";
+ ModuleSpec spec;
+ for (size_t i = 0; i < module_specs.GetSize(); ++i)
+ {
+ assert(module_specs.GetModuleSpecAtIndex(i, spec));
+ if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
+ (arch == NULL || (spec.GetArchitecturePtr() && spec.GetArchitecture().IsCompatibleMatch(*arch))))
+ {
+ return true;
+ }
+ }
}
+ return false;
+}
- // Get directory of our module. Needed to check debug files like this:
- // /usr/lib/debug/usr/lib/library.so.debug
- std::string module_directory = module_spec.GetFileSpec().GetDirectory().AsCString();
-
- size_t num_directories = debug_file_search_paths.GetSize();
- for (size_t idx = 0; idx < num_directories; ++idx)
+static bool
+LocateDSYMInVincinityOfExecutable (const ModuleSpec &module_spec, FileSpec &dsym_fspec)
+{
+ const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
+ if (exec_fspec)
{
- FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex (idx);
- dirspec.ResolvePath();
- if (!dirspec.Exists() || !dirspec.IsDirectory())
- continue;
-
- std::vector<std::string> files;
- std::string dirname = dirspec.GetPath();
-
- files.push_back (dirname + "/" + symbol_filename);
- files.push_back (dirname + "/.debug/" + symbol_filename);
- files.push_back (dirname + "/.build-id/" + uuid_str);
- files.push_back (dirname + module_directory + "/" + symbol_filename);
-
- const uint32_t num_files = files.size();
- for (size_t idx_file = 0; idx_file < num_files; ++idx_file)
+ char path[PATH_MAX];
+ if (exec_fspec->GetPath(path, sizeof(path)))
{
- const std::string &filename = files[idx_file];
- FileSpec file_spec (filename.c_str(), true);
+ // Make sure the module isn't already just a dSYM file...
+ if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL)
+ {
+ size_t obj_file_path_length = strlen(path);
+ ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1);
+ ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1);
- if (file_spec == module_spec.GetFileSpec())
- continue;
+ dsym_fspec.SetFile(path, false);
- if (file_spec.Exists())
- {
- lldb_private::ModuleSpecList specs;
- const size_t num_specs = ObjectFile::GetModuleSpecifications (file_spec, 0, 0, specs);
- assert (num_specs <= 1 && "Symbol Vendor supports only a single architecture");
- if (num_specs == 1)
+ ModuleSpecList module_specs;
+ ModuleSpec matched_module_spec;
+ if (dsym_fspec.Exists() &&
+ FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
{
- ModuleSpec mspec;
- if (specs.GetModuleSpecAtIndex (0, mspec))
+ return true;
+ }
+ else
+ {
+ path[obj_file_path_length] = '\0';
+
+ char *last_dot = strrchr(path, '.');
+ while (last_dot != NULL && last_dot[0])
{
- if (mspec.GetUUID() == module_uuid)
- return file_spec;
+ char *next_slash = strchr(last_dot, '/');
+ if (next_slash != NULL)
+ {
+ *next_slash = '\0';
+ ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1);
+ ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1);
+ dsym_fspec.SetFile(path, false);
+ if (dsym_fspec.Exists() &&
+ FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
+ {
+ return true;
+ }
+ else
+ {
+ *last_dot = '\0';
+ char *prev_slash = strrchr(path, '/');
+ if (prev_slash != NULL)
+ *prev_slash = '\0';
+ else
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
}
}
}
}
}
-
- return FileSpec();
+ dsym_fspec.Clear();
+ return false;
}
FileSpec
-Symbols::FindSymbolFileInBundle (const FileSpec& symfile_bundle,
- const lldb_private::UUID *uuid,
- const ArchSpec *arch)
+LocateExecutableSymbolFileDsym (const ModuleSpec &module_spec)
{
- // FIXME
- return FileSpec();
-}
+ const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
+ const ArchSpec *arch = module_spec.GetArchitecturePtr();
+ const UUID *uuid = module_spec.GetUUIDPtr();
-bool
-Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup)
-{
- // Fill in the module_spec.GetFileSpec() for the object file and/or the
- // module_spec.GetSymbolFileSpec() for the debug symbols file.
- return false;
-}
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)",
+ exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
+ arch ? arch->GetArchitectureName() : "<NULL>",
+ (void*)uuid);
-#elif !defined (__APPLE__)
+ FileSpec symbol_fspec;
+ // First try and find the dSYM in the same directory as the executable or in
+ // an appropriate parent directory
+ if (LocateDSYMInVincinityOfExecutable (module_spec, symbol_fspec) == false)
+ {
+ // We failed to easily find the dSYM above, so use DebugSymbols
+ LocateMacOSXFilesUsingDebugSymbols (module_spec, NULL, &symbol_fspec);
+ }
+ return symbol_fspec;
+}
FileSpec
Symbols::LocateExecutableObjectFile (const ModuleSpec &module_spec)
{
- // FIXME
- return FileSpec();
+ const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
+ const ArchSpec *arch = module_spec.GetArchitecturePtr();
+ const UUID *uuid = module_spec.GetUUIDPtr();
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
+ exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
+ arch ? arch->GetArchitectureName() : "<NULL>",
+ (void*)uuid);
+
+ FileSpec objfile_fspec;
+ ModuleSpecList module_specs;
+ ModuleSpec matched_module_spec;
+ if (exec_fspec &&
+ ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) &&
+ module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
+ {
+ objfile_fspec = exec_fspec;
+ }
+ else
+ {
+ LocateMacOSXFilesUsingDebugSymbols (module_spec, &objfile_fspec, NULL);
+ }
+ return objfile_fspec;
}
FileSpec
Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec)
{
- // FIXME
- return FileSpec();
+ const char *symbol_filename = module_spec.GetSymbolFileSpec().GetFilename().AsCString();
+ if (symbol_filename && symbol_filename[0])
+ {
+ FileSpecList debug_file_search_paths (Target::GetDefaultDebugFileSearchPaths());
+
+ // Add module directory.
+ const ConstString &file_dir = module_spec.GetFileSpec().GetDirectory();
+ debug_file_search_paths.AppendIfUnique (FileSpec(file_dir.AsCString("."), true));
+
+ // Add current working directory.
+ debug_file_search_paths.AppendIfUnique (FileSpec(".", true));
+
+ // Add /usr/lib/debug directory.
+ debug_file_search_paths.AppendIfUnique (FileSpec("/usr/lib/debug", true));
+
+ std::string uuid_str;
+ const UUID &module_uuid = module_spec.GetUUID();
+ if (module_uuid.IsValid())
+ {
+ // Some debug files are stored in the .build-id directory like this:
+ // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug
+ uuid_str = module_uuid.GetAsString("");
+ uuid_str.insert (2, 1, '/');
+ uuid_str = uuid_str + ".debug";
+ }
+
+ // Get directory of our module. Needed to check debug files like this:
+ // /usr/lib/debug/usr/lib/library.so.debug
+ std::string module_directory = module_spec.GetFileSpec().GetDirectory().AsCString();
+
+ size_t num_directories = debug_file_search_paths.GetSize();
+ for (size_t idx = 0; idx < num_directories; ++idx)
+ {
+ FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex (idx);
+ dirspec.ResolvePath();
+ if (!dirspec.Exists() || !dirspec.IsDirectory())
+ continue;
+
+ std::vector<std::string> files;
+ std::string dirname = dirspec.GetPath();
+
+ files.push_back (dirname + "/" + symbol_filename);
+ files.push_back (dirname + "/.debug/" + symbol_filename);
+ files.push_back (dirname + "/.build-id/" + uuid_str);
+ files.push_back (dirname + module_directory + "/" + symbol_filename);
+
+ const uint32_t num_files = files.size();
+ for (size_t idx_file = 0; idx_file < num_files; ++idx_file)
+ {
+ const std::string &filename = files[idx_file];
+ FileSpec file_spec (filename.c_str(), true);
+
+ if (llvm::sys::fs::equivalent (file_spec.GetPath(), module_spec.GetFileSpec().GetPath()))
+ continue;
+
+ if (file_spec.Exists())
+ {
+ lldb_private::ModuleSpecList specs;
+ const size_t num_specs = ObjectFile::GetModuleSpecifications (file_spec, 0, 0, specs);
+ assert (num_specs <= 1 && "Symbol Vendor supports only a single architecture");
+ if (num_specs == 1)
+ {
+ ModuleSpec mspec;
+ if (specs.GetModuleSpecAtIndex (0, mspec))
+ {
+ if (mspec.GetUUID() == module_uuid)
+ return file_spec;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return LocateExecutableSymbolFileDsym(module_spec);
}
+#if !defined (__APPLE__)
+
FileSpec
Symbols::FindSymbolFileInBundle (const FileSpec& symfile_bundle,
const lldb_private::UUID *uuid,
const ArchSpec *arch)
{
+ // FIXME
return FileSpec();
}
diff --git a/source/Host/common/Terminal.cpp b/source/Host/common/Terminal.cpp
index ca46eb0f744b..9f3abb75e919 100644
--- a/source/Host/common/Terminal.cpp
+++ b/source/Host/common/Terminal.cpp
@@ -180,20 +180,18 @@ TerminalState::Save (int fd, bool save_process_group)
bool
TerminalState::Restore () const
{
+#ifndef LLDB_DISABLE_POSIX
if (IsValid())
{
const int fd = m_tty.GetFileDescriptor();
-#ifndef LLDB_DISABLE_POSIX
if (TFlagsIsValid())
fcntl (fd, F_SETFL, m_tflags);
-#endif
#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
if (TTYStateIsValid())
tcsetattr (fd, TCSANOW, m_termios_ap.get());
#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
-#ifndef LLDB_DISABLE_POSIX
if (ProcessGroupIsValid())
{
// Save the original signal handler.
@@ -204,9 +202,9 @@ TerminalState::Restore () const
// Restore the original signal handler.
signal (SIGTTOU, saved_sigttou_callback);
}
-#endif
return true;
}
+#endif
return false;
}
diff --git a/source/Host/common/XML.cpp b/source/Host/common/XML.cpp
new file mode 100644
index 000000000000..14e786ab8b16
--- /dev/null
+++ b/source/Host/common/XML.cpp
@@ -0,0 +1,693 @@
+//===-- XML.cpp -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h> /* atof */
+
+#include "lldb/Host/XML.h"
+#include "lldb/Host/StringConvert.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+#pragma mark -- XMLDocument
+
+XMLDocument::XMLDocument () :
+ m_document (nullptr)
+{
+}
+
+XMLDocument::~XMLDocument ()
+{
+ Clear();
+}
+
+void
+XMLDocument::Clear()
+{
+#if defined( LIBXML2_DEFINED )
+ if (m_document)
+ {
+ xmlDocPtr doc = m_document;
+ m_document = nullptr;
+ xmlFreeDoc(doc);
+ }
+#endif
+}
+
+bool
+XMLDocument::IsValid() const
+{
+ return m_document != nullptr;
+}
+
+void
+XMLDocument::ErrorCallback (void *ctx, const char *format, ...)
+{
+ XMLDocument *document = (XMLDocument *)ctx;
+ va_list args;
+ va_start (args, format);
+ document->m_errors.PrintfVarArg(format, args);
+ document->m_errors.EOL();
+ va_end (args);
+}
+
+bool
+XMLDocument::ParseFile (const char *path)
+{
+#if defined( LIBXML2_DEFINED )
+ Clear();
+ xmlSetGenericErrorFunc( (void *)this, XMLDocument::ErrorCallback );
+ m_document = xmlParseFile(path);
+ xmlSetGenericErrorFunc(nullptr, nullptr);
+#endif
+ return IsValid();
+}
+
+bool
+XMLDocument::ParseMemory (const char *xml, size_t xml_length, const char *url)
+{
+#if defined( LIBXML2_DEFINED )
+ Clear();
+ xmlSetGenericErrorFunc( (void *)this, XMLDocument::ErrorCallback );
+ m_document = xmlReadMemory(xml, (int)xml_length, url, nullptr, 0);
+ xmlSetGenericErrorFunc(nullptr, nullptr);
+#endif
+ return IsValid();
+
+}
+
+XMLNode
+XMLDocument::GetRootElement(const char *required_name)
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ XMLNode root_node(xmlDocGetRootElement(m_document));
+ if (required_name)
+ {
+ llvm::StringRef actual_name = root_node.GetName();
+ if (actual_name == required_name)
+ return root_node;
+ }
+ else
+ {
+ return root_node;
+ }
+ }
+#endif
+ return XMLNode();
+}
+
+const std::string &
+XMLDocument::GetErrors() const
+{
+ return m_errors.GetString();
+}
+
+bool
+XMLDocument::XMLEnabled ()
+{
+#if defined( LIBXML2_DEFINED )
+ return true;
+#else
+ return false;
+#endif
+}
+
+#pragma mark -- XMLNode
+
+XMLNode::XMLNode() :
+ m_node(nullptr)
+{
+}
+
+XMLNode::XMLNode(XMLNodeImpl node) :
+ m_node(node)
+{
+}
+
+XMLNode::~XMLNode()
+{
+
+}
+
+void
+XMLNode::Clear()
+{
+ m_node = nullptr;
+}
+
+XMLNode
+XMLNode::GetParent() const
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ return XMLNode(m_node->parent);
+ else
+ return XMLNode();
+#else
+ return XMLNode();
+#endif
+
+}
+
+XMLNode
+XMLNode::GetSibling() const
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ return XMLNode(m_node->next);
+ else
+ return XMLNode();
+#else
+ return XMLNode();
+#endif
+
+}
+
+XMLNode
+XMLNode::GetChild () const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ return XMLNode(m_node->children);
+ else
+ return XMLNode();
+#else
+ return XMLNode();
+#endif
+
+}
+
+llvm::StringRef
+XMLNode::GetAttributeValue(const char *name, const char *fail_value) const
+{
+ const char *attr_value = NULL;
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ attr_value = (const char *)xmlGetProp(m_node, (const xmlChar *)name);
+ else
+ attr_value = fail_value;
+#else
+ attr_value = fail_value;
+#endif
+ if (attr_value)
+ return llvm::StringRef(attr_value);
+ else
+ return llvm::StringRef();
+}
+
+
+
+
+void
+XMLNode::ForEachChildNode (NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ GetChild().ForEachSiblingNode(callback);
+#endif
+}
+
+void
+XMLNode::ForEachChildElement (NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+ XMLNode child = GetChild();
+ if (child)
+ child.ForEachSiblingElement(callback);
+#endif
+}
+
+void
+XMLNode::ForEachChildElementWithName (const char *name, NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+ XMLNode child = GetChild();
+ if (child)
+ child.ForEachSiblingElementWithName(name, callback);
+#endif
+}
+
+void
+XMLNode::ForEachAttribute (AttributeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ for (xmlAttrPtr attr = m_node->properties; attr != nullptr; attr=attr->next)
+ {
+ // check if name matches
+ if (attr->name)
+ {
+ // check child is a text node
+ xmlNodePtr child = attr->children;
+ if (child->type == XML_TEXT_NODE)
+ {
+ llvm::StringRef attr_value;
+ if (child->content)
+ attr_value = llvm::StringRef((const char *)child->content);
+ if (callback(llvm::StringRef((const char *)attr->name), attr_value) == false)
+ return;
+ }
+ }
+ }
+ }
+#endif
+}
+
+
+void
+XMLNode::ForEachSiblingNode (NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ // iterate through all siblings
+ for (xmlNodePtr node = m_node; node; node=node->next)
+ {
+ if (callback(XMLNode(node)) == false)
+ return;
+ }
+ }
+#endif
+}
+
+void
+XMLNode::ForEachSiblingElement (NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ // iterate through all siblings
+ for (xmlNodePtr node = m_node; node; node=node->next)
+ {
+ // we are looking for element nodes only
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (callback(XMLNode(node)) == false)
+ return;
+ }
+ }
+#endif
+}
+
+void
+XMLNode::ForEachSiblingElementWithName (const char *name, NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ // iterate through all siblings
+ for (xmlNodePtr node = m_node; node; node=node->next)
+ {
+ // we are looking for element nodes only
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+
+ // If name is nullptr, we take all nodes of type "t", else
+ // just the ones whose name matches
+ if (name)
+ {
+ if (strcmp((const char *)node->name, name) != 0)
+ continue; // Name mismatch, ignore this one
+ }
+ else
+ {
+ if (node->name)
+ continue; // nullptr name specified and this elemnt has a name, ignore this one
+ }
+
+ if (callback(XMLNode(node)) == false)
+ return;
+ }
+ }
+#endif
+}
+
+llvm::StringRef
+XMLNode::GetName() const
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ if (m_node->name)
+ return llvm::StringRef((const char *)m_node->name);
+ }
+#endif
+ return llvm::StringRef();
+}
+
+bool
+XMLNode::GetElementText (std::string &text) const
+{
+ text.clear();
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ bool success = false;
+ if (m_node->type == XML_ELEMENT_NODE)
+ {
+ // check child is a text node
+ for (xmlNodePtr node = m_node->children;
+ node != nullptr;
+ node = node->next)
+ {
+ if (node->type == XML_TEXT_NODE)
+ {
+ text.append((const char *)node->content);
+ success = true;
+ }
+ }
+ }
+ return success;
+ }
+#endif
+ return false;
+}
+
+
+bool
+XMLNode::GetElementTextAsUnsigned (uint64_t &value, uint64_t fail_value, int base) const
+{
+ bool success = false;
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ std::string text;
+ if (GetElementText(text))
+ value = StringConvert::ToUInt64(text.c_str(), fail_value, base, &success);
+ }
+#endif
+ if (!success)
+ value = fail_value;
+ return success;
+}
+
+bool
+XMLNode::GetElementTextAsFloat (double &value, double fail_value) const
+{
+ bool success = false;
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ std::string text;
+ if (GetElementText(text))
+ {
+ value = atof(text.c_str());
+ success = true;
+ }
+ }
+#endif
+ if (!success)
+ value = fail_value;
+ return success;
+}
+
+
+
+bool
+XMLNode::NameIs (const char *name) const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ // In case we are looking for a nullptr name or an exact pointer match
+ if (m_node->name == (const xmlChar *)name)
+ return true;
+ if (m_node->name)
+ return strcmp((const char *)m_node->name, name) == 0;
+ }
+#endif
+ return false;
+}
+
+XMLNode
+XMLNode::FindFirstChildElementWithName (const char *name) const
+{
+ XMLNode result_node;
+
+#if defined( LIBXML2_DEFINED )
+ ForEachChildElementWithName(name, [&result_node, name](const XMLNode& node) -> bool {
+ result_node = node;
+ // Stop iterating, we found the node we wanted
+ return false;
+ });
+#endif
+
+ return result_node;
+}
+
+bool
+XMLNode::IsValid() const
+{
+ return m_node != nullptr;
+}
+
+bool
+XMLNode::IsElement () const
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ return m_node->type == XML_ELEMENT_NODE;
+#endif
+ return false;
+}
+
+
+XMLNode
+XMLNode::GetElementForPath (const NamePath &path)
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ if (path.empty())
+ return *this;
+ else
+ {
+ XMLNode node = FindFirstChildElementWithName(path[0].c_str());
+ const size_t n = path.size();
+ for (size_t i=1; node && i<n; ++i)
+ node = node.FindFirstChildElementWithName(path[i].c_str());
+ return node;
+ }
+ }
+#endif
+
+ return XMLNode();
+}
+
+
+#pragma mark -- ApplePropertyList
+
+ApplePropertyList::ApplePropertyList() :
+ m_xml_doc(),
+ m_dict_node()
+{
+
+}
+
+ApplePropertyList::ApplePropertyList (const char *path) :
+ m_xml_doc(),
+ m_dict_node()
+{
+ ParseFile(path);
+}
+
+ApplePropertyList::~ApplePropertyList()
+{
+}
+
+const std::string &
+ApplePropertyList::GetErrors() const
+{
+ return m_xml_doc.GetErrors();
+}
+
+
+bool
+ApplePropertyList::ParseFile (const char *path)
+{
+ if (m_xml_doc.ParseFile(path))
+ {
+ XMLNode plist = m_xml_doc.GetRootElement("plist");
+ if (plist)
+ {
+ plist.ForEachChildElementWithName("dict", [this](const XMLNode &dict) -> bool {
+ this->m_dict_node = dict;
+ return false; // Stop iterating
+ });
+ return (bool)m_dict_node;
+ }
+ }
+ return false;
+}
+
+bool
+ApplePropertyList::IsValid() const
+{
+ return (bool)m_dict_node;
+}
+
+bool
+ApplePropertyList::GetValueAsString (const char *key, std::string &value) const
+{
+ XMLNode value_node = GetValueNode (key);
+ if (value_node)
+ return ApplePropertyList::ExtractStringFromValueNode(value_node, value);
+ return false;
+}
+
+XMLNode
+ApplePropertyList::GetValueNode (const char *key) const
+{
+ XMLNode value_node;
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ m_dict_node.ForEachChildElementWithName("key", [key, &value_node](const XMLNode &key_node) -> bool {
+ std::string key_name;
+ if (key_node.GetElementText(key_name))
+ {
+ if (key_name.compare(key) == 0)
+ {
+ value_node = key_node.GetSibling();
+ while (value_node && !value_node.IsElement())
+ value_node = value_node.GetSibling();
+ return false; // Stop iterating
+ }
+ }
+ return true; // Keep iterating
+ });
+ }
+#endif
+ return value_node;
+}
+
+bool
+ApplePropertyList::ExtractStringFromValueNode (const XMLNode &node, std::string &value)
+{
+ value.clear();
+#if defined( LIBXML2_DEFINED )
+ if (node.IsValid())
+ {
+ llvm::StringRef element_name = node.GetName();
+ if (element_name == "true" || element_name == "false")
+ {
+ // The text value _is_ the element name itself...
+ value = std::move(element_name.str());
+ return true;
+ }
+ else if (element_name == "dict" || element_name == "array")
+ return false; // dictionaries and arrays have no text value, so we fail
+ else
+ return node.GetElementText(value);
+ }
+#endif
+ return false;
+}
+
+#if defined( LIBXML2_DEFINED )
+
+namespace {
+
+ StructuredData::ObjectSP
+ CreatePlistValue (XMLNode node)
+ {
+ llvm::StringRef element_name = node.GetName();
+ if (element_name == "array")
+ {
+ std::shared_ptr<StructuredData::Array> array_sp(new StructuredData::Array());
+ node.ForEachChildElement([&array_sp](const XMLNode &node) -> bool {
+ array_sp->AddItem(CreatePlistValue(node));
+ return true; // Keep iterating through all child elements of the array
+ });
+ return array_sp;
+ }
+ else if (element_name == "dict")
+ {
+ XMLNode key_node;
+ std::shared_ptr<StructuredData::Dictionary> dict_sp(new StructuredData::Dictionary());
+ node.ForEachChildElement([&key_node, &dict_sp](const XMLNode &node) -> bool {
+ if (node.NameIs("key"))
+ {
+ // This is a "key" element node
+ key_node = node;
+ }
+ else
+ {
+ // This is a value node
+ if (key_node)
+ {
+ std::string key_name;
+ key_node.GetElementText(key_name);
+ dict_sp->AddItem(key_name, CreatePlistValue(node));
+ key_node.Clear();
+ }
+ }
+ return true; // Keep iterating through all child elements of the dictionary
+ });
+ return dict_sp;
+ }
+ else if (element_name == "real")
+ {
+ double value = 0.0;
+ node.GetElementTextAsFloat(value);
+ return StructuredData::ObjectSP(new StructuredData::Float(value));
+ }
+ else if (element_name == "integer")
+ {
+ uint64_t value = 0;
+ node.GetElementTextAsUnsigned(value, 0, 0);
+ return StructuredData::ObjectSP(new StructuredData::Integer(value));
+ }
+ else if ((element_name == "string") || (element_name == "data") || (element_name == "date"))
+ {
+ std::string text;
+ node.GetElementText(text);
+ return StructuredData::ObjectSP(new StructuredData::String(std::move(text)));
+ }
+ else if (element_name == "true")
+ {
+ return StructuredData::ObjectSP(new StructuredData::Boolean(true));
+ }
+ else if (element_name == "false")
+ {
+ return StructuredData::ObjectSP(new StructuredData::Boolean(false));
+ }
+ return StructuredData::ObjectSP(new StructuredData::Null());
+ }
+}
+#endif
+
+StructuredData::ObjectSP
+ApplePropertyList::GetStructuredData()
+{
+ StructuredData::ObjectSP root_sp;
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ return CreatePlistValue(m_dict_node);
+ }
+#endif
+ return root_sp;
+}
+
+
diff --git a/source/Host/freebsd/Host.cpp b/source/Host/freebsd/Host.cpp
index 2cbf4d8f4696..8b1c580af27d 100644
--- a/source/Host/freebsd/Host.cpp
+++ b/source/Host/freebsd/Host.cpp
@@ -38,6 +38,7 @@
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Utility/CleanUp.h"
+#include "lldb/Utility/NameMatches.h"
#include "Plugins/Process/Utility/FreeBSDSignals.h"
@@ -50,35 +51,6 @@ extern "C" {
using namespace lldb;
using namespace lldb_private;
-void
-Host::Backtrace (Stream &strm, uint32_t max_frames)
-{
- char backtrace_path[] = "/tmp/lldb-backtrace-tmp-XXXXXX";
- int backtrace_fd = ::mkstemp (backtrace_path);
- if (backtrace_fd != -1)
- {
- std::vector<void *> frame_buffer (max_frames, NULL);
- int count = ::backtrace (&frame_buffer[0], frame_buffer.size());
- ::backtrace_symbols_fd (&frame_buffer[0], count, backtrace_fd);
-
- const off_t buffer_size = ::lseek(backtrace_fd, 0, SEEK_CUR);
-
- if (::lseek(backtrace_fd, 0, SEEK_SET) == 0)
- {
- char *buffer = (char *)::malloc (buffer_size);
- if (buffer)
- {
- ssize_t bytes_read = ::read (backtrace_fd, buffer, buffer_size);
- if (bytes_read > 0)
- strm.Write(buffer, bytes_read);
- ::free (buffer);
- }
- }
- ::close (backtrace_fd);
- ::unlink (backtrace_path);
- }
-}
-
size_t
Host::GetEnvironment (StringList &env)
{
@@ -312,3 +284,9 @@ Host::GetUnixSignals ()
return s_unix_signals_sp;
}
+Error
+Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
+{
+ return Error("unimplemented");
+}
+
diff --git a/source/Host/freebsd/HostThreadFreeBSD.cpp b/source/Host/freebsd/HostThreadFreeBSD.cpp
index 7d611bb6894b..a4302a9e67bf 100644
--- a/source/Host/freebsd/HostThreadFreeBSD.cpp
+++ b/source/Host/freebsd/HostThreadFreeBSD.cpp
@@ -14,7 +14,9 @@
// C includes
#include <errno.h>
#include <pthread.h>
+#if defined (__FreeBSD__)
#include <pthread_np.h>
+#endif
#include <stdlib.h>
#include <sys/sysctl.h>
#include <sys/user.h>
diff --git a/source/Host/freebsd/ThisThread.cpp b/source/Host/freebsd/ThisThread.cpp
index fb25847be24f..e524fd4ace34 100644
--- a/source/Host/freebsd/ThisThread.cpp
+++ b/source/Host/freebsd/ThisThread.cpp
@@ -13,18 +13,27 @@
#include "llvm/ADT/SmallVector.h"
#include <pthread.h>
+#if defined (__FreeBSD__)
#include <pthread_np.h>
+#endif
using namespace lldb_private;
void
ThisThread::SetName(llvm::StringRef name)
{
+#if defined (__FreeBSD__) // Kfreebsd does not have a simple alternative
::pthread_set_name_np(::pthread_self(), name.data());
+#endif
}
void
ThisThread::GetName(llvm::SmallVectorImpl<char> &name)
{
+#if defined (__FreeBSD__)
HostNativeThread::GetName(::pthread_getthreadid_np(), name);
+#else
+// Kfreebsd
+ HostNativeThread::GetName((unsigned)pthread_self(), name);
+#endif
}
diff --git a/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/source/Host/posix/ConnectionFileDescriptorPosix.cpp
index fe70c33bf5ae..f12f98c30b44 100644
--- a/source/Host/posix/ConnectionFileDescriptorPosix.cpp
+++ b/source/Host/posix/ConnectionFileDescriptorPosix.cpp
@@ -39,7 +39,6 @@
#include "llvm/ADT/SmallVector.h"
#endif
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Communication.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/StreamString.h"
@@ -82,6 +81,17 @@ ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd)
OpenCommandPipe();
}
+ConnectionFileDescriptor::ConnectionFileDescriptor(Socket* socket)
+ : Connection()
+ , m_pipe()
+ , m_mutex(Mutex::eMutexTypeRecursive)
+ , m_shutting_down(false)
+ , m_waiting_for_accept(false)
+ , m_child_processes_inherit(false)
+{
+ InitializeSocket(socket);
+}
+
ConnectionFileDescriptor::~ConnectionFileDescriptor()
{
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
@@ -156,6 +166,14 @@ ConnectionFileDescriptor::Connect(const char *s, Error *error_ptr)
// unix://SOCKNAME
return NamedSocketAccept(s + strlen("unix-accept://"), error_ptr);
}
+ else if (strstr(s, "adb://") == s)
+ {
+ int port = -1;
+ sscanf(s, "adb://%*[^:]:%d", &port);
+ char host_and_port[sizeof("localhost:65535")];
+ snprintf(host_and_port, sizeof(host_and_port), "localhost:%d", port);
+ return ConnectTCP(host_and_port, error_ptr);
+ }
else if (strstr(s, "connect://") == s)
{
return ConnectTCP(s + strlen("connect://"), error_ptr);
@@ -354,6 +372,9 @@ ConnectionFileDescriptor::Disconnect(Error *error_ptr)
if (error_ptr)
*error_ptr = error.Fail() ? error : error2;
+ // Close any pipes we were using for async interrupts
+ m_pipe.Close();
+
m_uri.clear();
m_shutting_down = false;
return status;
@@ -376,8 +397,12 @@ ConnectionFileDescriptor::Read(void *dst, size_t dst_len, uint32_t timeout_usec,
status = eConnectionStatusTimedOut;
return 0;
}
- else if (m_shutting_down)
- return eConnectionStatusError;
+
+ if (m_shutting_down)
+ {
+ status = eConnectionStatusError;
+ return 0;
+ }
status = BytesAvailable(timeout_usec, error_ptr);
if (status != eConnectionStatusSuccess)
@@ -671,8 +696,10 @@ ConnectionFileDescriptor::BytesAvailable(uint32_t timeout_usec, Error *error_ptr
return eConnectionStatusSuccess;
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];
+ // There is an interrupt or exit command in the command pipe
+ // Read the data from that pipe:
+ char buffer[1];
+
ssize_t bytes_read;
do
@@ -684,8 +711,9 @@ ConnectionFileDescriptor::BytesAvailable(uint32_t timeout_usec, Error *error_ptr
{
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);
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() "
+ "got data: %c from the command channel.",
+ static_cast<void *>(this), buffer[0]);
return eConnectionStatusEndOfFile;
case 'i':
// Interrupt the current read
@@ -759,15 +787,7 @@ ConnectionFileDescriptor::SocketListenAndAccept(const char *s, Error *error_ptr)
if (error.Fail())
return eConnectionStatusError;
- m_write_sp.reset(socket);
- m_read_sp = m_write_sp;
- if (error.Fail())
- {
- return eConnectionStatusError;
- }
- StreamString strm;
- strm.Printf("connect://%s:%u",socket->GetRemoteIPAddress().c_str(), socket->GetRemotePortNumber());
- m_uri.swap(strm.GetString());
+ InitializeSocket(socket);
return eConnectionStatusSuccess;
}
@@ -832,3 +852,13 @@ ConnectionFileDescriptor::SetChildProcessesInherit(bool child_processes_inherit)
{
m_child_processes_inherit = child_processes_inherit;
}
+
+void
+ConnectionFileDescriptor::InitializeSocket(Socket* socket)
+{
+ m_write_sp.reset(socket);
+ m_read_sp = m_write_sp;
+ StreamString strm;
+ strm.Printf("connect://%s:%u",socket->GetRemoteIPAddress().c_str(), socket->GetRemotePortNumber());
+ m_uri.swap(strm.GetString());
+}
diff --git a/source/Host/posix/FileSystem.cpp b/source/Host/posix/FileSystem.cpp
index 571316811142..52698039b46e 100644
--- a/source/Host/posix/FileSystem.cpp
+++ b/source/Host/posix/FileSystem.cpp
@@ -10,8 +10,16 @@
#include "lldb/Host/FileSystem.h"
// C includes
+#include <dirent.h>
+#include <sys/mount.h>
+#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
+#ifdef __linux__
+#include <sys/statfs.h>
+#include <sys/mount.h>
+#include <linux/magic.h>
+#endif
// lldb Includes
#include "lldb/Core/Error.h"
@@ -28,70 +36,91 @@ FileSystem::GetNativePathSyntax()
}
Error
-FileSystem::MakeDirectory(const char *path, uint32_t file_permissions)
+FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions)
{
- Error error;
- if (path && path[0])
+ if (file_spec)
{
- if (::mkdir(path, file_permissions) != 0)
+ Error error;
+ if (::mkdir(file_spec.GetCString(), file_permissions) == -1)
{
error.SetErrorToErrno();
+ errno = 0;
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
+ FileSpec parent_file_spec{file_spec.GetDirectory().GetCString(), false};
+ error = MakeDirectory(parent_file_spec, file_permissions);
+ if (error.Fail())
+ return error;
+ // Try and make the directory again now that the parent directory was made successfully
+ if (::mkdir(file_spec.GetCString(), file_permissions) == -1)
{
- // 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();
- }
+ error.SetErrorToErrno();
+ return error;
}
}
- break;
-
case EEXIST:
{
- FileSpec path_spec(path, false);
- if (path_spec.IsDirectory())
- error.Clear(); // It is a directory and it already exists
+ if (file_spec.IsDirectory())
+ return Error{}; // It is a directory and it already exists
}
- break;
}
}
+ return error;
}
- else
- {
- error.SetErrorString("empty path");
- }
- return error;
+ return Error{"empty path"};
}
Error
-FileSystem::DeleteDirectory(const char *path, bool recurse)
+FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse)
{
Error error;
- if (path && path[0])
+ if (file_spec)
{
if (recurse)
{
- StreamString command;
- command.Printf("rm -rf \"%s\"", path);
- int status = ::system(command.GetString().c_str());
- if (status != 0)
- error.SetError(status, eErrorTypeGeneric);
+ // Save all sub directories in a list so we don't recursively call this function
+ // and possibly run out of file descriptors if the directory is too deep.
+ std::vector<FileSpec> sub_directories;
+
+ FileSpec::ForEachItemInDirectory (file_spec.GetCString(), [&error, &sub_directories](FileSpec::FileType file_type, const FileSpec &spec) -> FileSpec::EnumerateDirectoryResult {
+ if (file_type == FileSpec::eFileTypeDirectory)
+ {
+ // Save all directorires and process them after iterating through this directory
+ sub_directories.push_back(spec);
+ }
+ else
+ {
+ // Update sub_spec to point to the current file and delete it
+ error = FileSystem::Unlink(spec);
+ }
+ // If anything went wrong, stop iterating, else process the next file
+ if (error.Fail())
+ return FileSpec::eEnumerateDirectoryResultQuit;
+ else
+ return FileSpec::eEnumerateDirectoryResultNext;
+ });
+
+ if (error.Success())
+ {
+ // Now delete all sub directories with separate calls that aren't
+ // recursively calling into this function _while_ this function is
+ // iterating through the current directory.
+ for (const auto &sub_directory : sub_directories)
+ {
+ error = DeleteDirectory(sub_directory, recurse);
+ if (error.Fail())
+ break;
+ }
+ }
}
- else
+
+ if (error.Success())
{
- if (::rmdir(path) != 0)
+ if (::rmdir(file_spec.GetCString()) != 0)
error.SetErrorToErrno();
}
}
@@ -103,11 +132,11 @@ FileSystem::DeleteDirectory(const char *path, bool recurse)
}
Error
-FileSystem::GetFilePermissions(const char *path, uint32_t &file_permissions)
+FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions)
{
Error error;
struct stat file_stats;
- if (::stat(path, &file_stats) == 0)
+ if (::stat(file_spec.GetCString(), &file_stats) == 0)
{
// The bits in "st_mode" currently match the definitions
// for the file mode bits in unix.
@@ -121,10 +150,10 @@ FileSystem::GetFilePermissions(const char *path, uint32_t &file_permissions)
}
Error
-FileSystem::SetFilePermissions(const char *path, uint32_t file_permissions)
+FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions)
{
Error error;
- if (::chmod(path, file_permissions) != 0)
+ if (::chmod(file_spec.GetCString(), file_permissions) != 0)
error.SetErrorToErrno();
return error;
}
@@ -142,60 +171,72 @@ FileSystem::GetFileExists(const FileSpec &file_spec)
}
Error
-FileSystem::Symlink(const char *src, const char *dst)
+FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst)
{
Error error;
- if (::symlink(dst, src) == -1)
+ if (::link(dst.GetCString(), src.GetCString()) == -1)
error.SetErrorToErrno();
return error;
}
Error
-FileSystem::Unlink(const char *path)
+FileSystem::Symlink(const FileSpec &src, const FileSpec &dst)
{
Error error;
- if (::unlink(path) == -1)
+ if (::symlink(dst.GetCString(), src.GetCString()) == -1)
error.SetErrorToErrno();
return error;
}
Error
-FileSystem::Readlink(const char *path, char *buf, size_t buf_len)
+FileSystem::Unlink(const FileSpec &file_spec)
{
Error error;
- ssize_t count = ::readlink(path, buf, buf_len);
+ if (::unlink(file_spec.GetCString()) == -1)
+ error.SetErrorToErrno();
+ return error;
+}
+
+Error
+FileSystem::Readlink(const FileSpec &src, FileSpec &dst)
+{
+ Error error;
+ char buf[PATH_MAX];
+ ssize_t count = ::readlink(src.GetCString(), buf, sizeof(buf) - 1);
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");
+ {
+ buf[count] = '\0'; // Success
+ dst.SetFile(buf, false);
+ }
return error;
}
-bool
-FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high)
+static bool IsLocal(const struct statfs& info)
{
-#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)
+#ifdef __linux__
+ #define CIFS_MAGIC_NUMBER 0xFF534D42
+ switch ((uint32_t)info.f_type)
+ {
+ case NFS_SUPER_MAGIC:
+ case SMB_SUPER_MAGIC:
+ case CIFS_MAGIC_NUMBER:
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;
+ default:
+ return true;
+ }
#else
- // your own MD5 implementation here
- return false;
+ return (info.f_flags & MNT_LOCAL) != 0;
#endif
}
+
+bool
+FileSystem::IsLocal(const FileSpec &spec)
+{
+ struct statfs statfs_info;
+ std::string path (spec.GetPath());
+ if (statfs(path.c_str(), &statfs_info) == 0)
+ return ::IsLocal(statfs_info);
+ return false;
+}
diff --git a/source/Host/posix/HostInfoPosix.cpp b/source/Host/posix/HostInfoPosix.cpp
index 018d423ee9d3..c04db71e1b81 100644
--- a/source/Host/posix/HostInfoPosix.cpp
+++ b/source/Host/posix/HostInfoPosix.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "lldb/lldb-python.h"
-
#include "lldb/Core/Log.h"
#include "lldb/Host/posix/HostInfoPosix.h"
@@ -17,6 +16,7 @@
#include <grp.h>
#include <limits.h>
+#include <mutex>
#include <netdb.h>
#include <pwd.h>
#include <sys/types.h>
@@ -47,9 +47,31 @@ HostInfoPosix::GetHostname(std::string &s)
return false;
}
+#ifdef __ANDROID_NDK__
+#include <android/api-level.h>
+#endif
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+#define USE_GETPWUID
+#endif
+
+#ifdef USE_GETPWUID
+static std::mutex s_getpwuid_lock;
+#endif
+
const char *
HostInfoPosix::LookupUserName(uint32_t uid, std::string &user_name)
{
+#ifdef USE_GETPWUID
+ // getpwuid_r is missing from android-9
+ // make getpwuid thread safe with a mutex
+ std::lock_guard<std::mutex> lock(s_getpwuid_lock);
+ struct passwd *user_info_ptr = ::getpwuid(uid);
+ if (user_info_ptr)
+ {
+ user_name.assign(user_info_ptr->pw_name);
+ return user_name.c_str();
+ }
+#else
struct passwd user_info;
struct passwd *user_info_ptr = &user_info;
char user_buffer[PATH_MAX];
@@ -62,8 +84,9 @@ HostInfoPosix::LookupUserName(uint32_t uid, std::string &user_name)
return user_name.c_str();
}
}
+#endif
user_name.clear();
- return NULL;
+ return nullptr;
}
const char *
@@ -153,11 +176,8 @@ HostInfoPosix::ComputeSupportExeDirectory(FileSpec &file_spec)
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));
+ ::snprintf(lib_pos, PATH_MAX - (lib_pos - raw_path), "/bin");
if (log)
log->Printf("Host::%s() derived the bin path as: %s", __FUNCTION__, raw_path);
diff --git a/source/Host/posix/HostProcessPosix.cpp b/source/Host/posix/HostProcessPosix.cpp
index 8e19add048ee..5761a79da27f 100644
--- a/source/Host/posix/HostProcessPosix.cpp
+++ b/source/Host/posix/HostProcessPosix.cpp
@@ -69,28 +69,25 @@ Error HostProcessPosix::GetMainModule(FileSpec &file_spec) const
// 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_process) <= 0)
+ if (snprintf(link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", m_process) != 1)
{
error.SetErrorString("Unable to build /proc/<pid>/exe string");
return error;
}
- error = FileSystem::Readlink(link_path, exe_path, llvm::array_lengthof(exe_path));
+ error = FileSystem::Readlink(FileSpec{link_path, false}, file_spec);
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)"))
+ if (file_spec.GetFilename().GetStringRef().endswith(" (deleted)"))
{
- exe_path[len - deleted_len] = 0;
+ const char *filename = file_spec.GetFilename().GetCString();
+ static const size_t deleted_len = strlen(" (deleted)");
+ const size_t len = file_spec.GetFilename().GetLength();
+ file_spec.GetFilename().SetCStringWithLength(filename, len - deleted_len);
}
-
- file_spec.SetFile(exe_path, false);
return error;
}
diff --git a/source/Host/posix/LockFilePosix.cpp b/source/Host/posix/LockFilePosix.cpp
new file mode 100644
index 000000000000..e52b648799b7
--- /dev/null
+++ b/source/Host/posix/LockFilePosix.cpp
@@ -0,0 +1,77 @@
+//===-- LockFilePosix.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/LockFilePosix.h"
+
+#include <fcntl.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+
+Error fileLock (int fd, int cmd, int lock_type, const uint64_t start, const uint64_t len)
+{
+ struct flock fl;
+
+ fl.l_type = lock_type;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = start;
+ fl.l_len = len;
+ fl.l_pid = ::getpid ();
+
+ Error error;
+ if (::fcntl (fd, cmd, &fl) == -1)
+ error.SetErrorToErrno ();
+
+ return error;
+}
+
+} // namespace
+
+LockFilePosix::LockFilePosix (int fd)
+ : LockFileBase (fd)
+{
+}
+
+LockFilePosix::~LockFilePosix ()
+{
+ Unlock ();
+}
+
+Error
+LockFilePosix::DoWriteLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_fd, F_SETLKW, F_WRLCK, start, len);
+}
+
+Error
+LockFilePosix::DoTryWriteLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_fd, F_SETLK, F_WRLCK, start, len);
+}
+
+Error
+LockFilePosix::DoReadLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_fd, F_SETLKW, F_RDLCK, start, len);
+}
+
+Error
+LockFilePosix::DoTryReadLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_fd, F_SETLK, F_RDLCK, start, len);
+}
+
+Error
+LockFilePosix::DoUnlock ()
+{
+ return fileLock (m_fd, F_SETLK, F_UNLCK, m_start, m_len);
+}
diff --git a/source/Host/posix/PipePosix.cpp b/source/Host/posix/PipePosix.cpp
index 1650f1e7979b..0ed319facf93 100644
--- a/source/Host/posix/PipePosix.cpp
+++ b/source/Host/posix/PipePosix.cpp
@@ -129,9 +129,27 @@ SelectIO(int handle, bool is_read, const std::function<Error(bool&)> &io_handler
}
PipePosix::PipePosix()
+ : m_fds{
+ PipePosix::kInvalidDescriptor,
+ PipePosix::kInvalidDescriptor
+ } {}
+
+PipePosix::PipePosix(int read_fd, int write_fd)
+ : m_fds{read_fd, write_fd} {}
+
+PipePosix::PipePosix(PipePosix &&pipe_posix)
+ : PipeBase{std::move(pipe_posix)},
+ m_fds{
+ pipe_posix.ReleaseReadFileDescriptor(),
+ pipe_posix.ReleaseWriteFileDescriptor()
+ } {}
+
+PipePosix &PipePosix::operator=(PipePosix &&pipe_posix)
{
- m_fds[READ] = PipePosix::kInvalidDescriptor;
- m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ PipeBase::operator=(std::move(pipe_posix));
+ m_fds[READ] = pipe_posix.ReleaseReadFileDescriptor();
+ m_fds[WRITE] = pipe_posix.ReleaseWriteFileDescriptor();
+ return *this;
}
PipePosix::~PipePosix()
@@ -317,7 +335,7 @@ PipePosix::Close()
Error
PipePosix::Delete(llvm::StringRef name)
{
- return FileSystem::Unlink(name.data());
+ return FileSystem::Unlink(FileSpec{name.data(), true});
}
bool
diff --git a/source/Initialization/SystemInitializer.cpp b/source/Initialization/SystemInitializer.cpp
new file mode 100644
index 000000000000..5a60c04ba4f3
--- /dev/null
+++ b/source/Initialization/SystemInitializer.cpp
@@ -0,0 +1,20 @@
+//===-- SystemInitializer.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/Initialization/SystemInitializer.h"
+
+using namespace lldb_private;
+
+SystemInitializer::SystemInitializer()
+{
+}
+
+SystemInitializer::~SystemInitializer()
+{
+}
diff --git a/source/Initialization/SystemInitializerCommon.cpp b/source/Initialization/SystemInitializerCommon.cpp
new file mode 100644
index 000000000000..35189c103f7c
--- /dev/null
+++ b/source/Initialization/SystemInitializerCommon.cpp
@@ -0,0 +1,185 @@
+//===-- SystemInitializerCommon.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/Initialization/SystemInitializerCommon.h"
+
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+
+#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"
+#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
+#include "Plugins/Instruction/ARM/EmulateInstructionARM.h"
+#include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h"
+#include "Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h"
+#include "Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h"
+#include "Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h"
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
+#include "Plugins/OperatingSystem/Python/OperatingSystemPython.h"
+#include "Plugins/Platform/Android/PlatformAndroid.h"
+#include "Plugins/Platform/FreeBSD/PlatformFreeBSD.h"
+#include "Plugins/Platform/Kalimba/PlatformKalimba.h"
+#include "Plugins/Platform/Linux/PlatformLinux.h"
+#include "Plugins/Platform/MacOSX/PlatformiOSSimulator.h"
+#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
+#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
+#include "Plugins/Platform/Windows/PlatformWindows.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
+
+#if defined(__APPLE__)
+#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
+#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
+#include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h"
+#endif
+
+#if defined(__linux__)
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#endif
+
+#if defined(_MSC_VER)
+#include "lldb/Host/windows/windows.h"
+#include "Plugins/Process/Windows/ProcessWindowsLog.h"
+#endif
+
+#include "llvm/Support/TargetSelect.h"
+
+#include <string>
+
+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();
+}
+
+SystemInitializerCommon::SystemInitializerCommon()
+{
+}
+
+SystemInitializerCommon::~SystemInitializerCommon()
+{
+}
+
+void
+SystemInitializerCommon::Initialize()
+{
+#if defined(_MSC_VER)
+ const char *disable_crash_dialog_var = getenv("LLDB_DISABLE_CRASH_DIALOG");
+ if (disable_crash_dialog_var && llvm::StringRef(disable_crash_dialog_var).equals_lower("true"))
+ {
+ // This will prevent Windows from displaying a dialog box requiring user interaction when
+ // LLDB crashes. This is mostly useful when automating LLDB, for example via the test
+ // suite, so that a crash in LLDB does not prevent completion of the test suite.
+ ::SetErrorMode(GetErrorMode() | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
+ }
+#endif
+
+ Log::Initialize();
+ HostInfo::Initialize();
+ Timer::Initialize();
+ Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ llvm::install_fatal_error_handler(fatal_error_handler, 0);
+
+ process_gdb_remote::ProcessGDBRemoteLog::Initialize();
+
+ // Initialize plug-ins
+ ObjectContainerBSDArchive::Initialize();
+ ObjectFileELF::Initialize();
+ ObjectFilePECOFF::Initialize();
+ DynamicLoaderPOSIXDYLD::Initialize();
+ platform_freebsd::PlatformFreeBSD::Initialize();
+ platform_linux::PlatformLinux::Initialize();
+ PlatformWindows::Initialize();
+ PlatformKalimba::Initialize();
+ platform_android::PlatformAndroid::Initialize();
+
+ EmulateInstructionARM::Initialize();
+ EmulateInstructionMIPS::Initialize();
+ EmulateInstructionMIPS64::Initialize();
+
+ //----------------------------------------------------------------------
+ // Apple/Darwin hosted plugins
+ //----------------------------------------------------------------------
+ DynamicLoaderMacOSXDYLD::Initialize();
+ ObjectContainerUniversalMachO::Initialize();
+
+ PlatformRemoteiOS::Initialize();
+ PlatformMacOSX::Initialize();
+ PlatformiOSSimulator::Initialize();
+
+#if defined(__APPLE__)
+ DynamicLoaderDarwinKernel::Initialize();
+ PlatformDarwinKernel::Initialize();
+ ObjectFileMachO::Initialize();
+#endif
+#if defined(__linux__)
+ static ConstString g_linux_log_name("linux");
+ ProcessPOSIXLog::Initialize(g_linux_log_name);
+#endif
+#if defined(_MSC_VER)
+ ProcessWindowsLog::Initialize();
+#endif
+#ifndef LLDB_DISABLE_PYTHON
+ ScriptInterpreterPython::InitializePrivate();
+ OperatingSystemPython::Initialize();
+#endif
+}
+
+void
+SystemInitializerCommon::Terminate()
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+ ObjectContainerBSDArchive::Terminate();
+ ObjectFileELF::Terminate();
+ ObjectFilePECOFF::Terminate();
+ DynamicLoaderPOSIXDYLD::Terminate();
+ platform_freebsd::PlatformFreeBSD::Terminate();
+ platform_linux::PlatformLinux::Terminate();
+ PlatformWindows::Terminate();
+ PlatformKalimba::Terminate();
+ platform_android::PlatformAndroid::Terminate();
+ DynamicLoaderMacOSXDYLD::Terminate();
+ ObjectContainerUniversalMachO::Terminate();
+ PlatformMacOSX::Terminate();
+ PlatformRemoteiOS::Terminate();
+ PlatformiOSSimulator::Terminate();
+
+ EmulateInstructionARM::Terminate();
+ EmulateInstructionMIPS::Terminate();
+ EmulateInstructionMIPS64::Terminate();
+
+#if defined(__APPLE__)
+ DynamicLoaderDarwinKernel::Terminate();
+ ObjectFileMachO::Terminate();
+ PlatformDarwinKernel::Terminate();
+#endif
+
+#if defined(__WIN32__)
+ ProcessWindowsLog::Terminate();
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+ OperatingSystemPython::Terminate();
+#endif
+
+ Log::Terminate();
+}
diff --git a/source/Initialization/SystemLifetimeManager.cpp b/source/Initialization/SystemLifetimeManager.cpp
new file mode 100644
index 000000000000..eafbe68c9984
--- /dev/null
+++ b/source/Initialization/SystemLifetimeManager.cpp
@@ -0,0 +1,61 @@
+//===-- SystemLifetimeManager.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/Initialization/SystemLifetimeManager.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Initialization/SystemInitializer.h"
+
+#include <utility>
+
+using namespace lldb_private;
+
+SystemLifetimeManager::SystemLifetimeManager()
+ : m_mutex(Mutex::eMutexTypeRecursive)
+ , m_initialized(false)
+{
+}
+
+SystemLifetimeManager::~SystemLifetimeManager()
+{
+ assert(!m_initialized && "SystemLifetimeManager destroyed without calling Terminate!");
+}
+
+void
+SystemLifetimeManager::Initialize(std::unique_ptr<SystemInitializer> initializer,
+ LoadPluginCallbackType plugin_callback)
+{
+ Mutex::Locker locker(m_mutex);
+ if (!m_initialized)
+ {
+ assert(!m_initializer &&
+ "Attempting to call SystemLifetimeManager::Initialize() when it is already initialized");
+ m_initialized = true;
+ m_initializer = std::move(initializer);
+
+ m_initializer->Initialize();
+ Debugger::Initialize(plugin_callback);
+ }
+}
+
+void
+SystemLifetimeManager::Terminate()
+{
+ Mutex::Locker locker(m_mutex);
+
+ if (m_initialized)
+ {
+ Debugger::Terminate();
+ m_initializer->Terminate();
+
+ m_initializer.reset();
+ m_initialized = false;
+ }
+}
diff --git a/source/Interpreter/Args.cpp b/source/Interpreter/Args.cpp
index 4f0219fb858b..2258c26e6c39 100644
--- a/source/Interpreter/Args.cpp
+++ b/source/Interpreter/Args.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
#include <cstdlib>
// C++ Includes
@@ -33,25 +31,15 @@ using namespace lldb_private;
//----------------------------------------------------------------------
// Args constructor
//----------------------------------------------------------------------
-Args::Args (const char *command) :
+Args::Args (llvm::StringRef command) :
m_args(),
m_argv(),
m_args_quote_char()
{
- if (command)
- SetCommandString (command);
+ SetCommandString (command);
}
-Args::Args (const char *command, size_t len) :
- m_args(),
- m_argv(),
- m_args_quote_char()
-{
- if (command && len)
- SetCommandString (command, len);
-}
-
//----------------------------------------------------------------------
// We have to be very careful on the copy constructor of this class
// to make sure we copy all of the string values, but we can't copy the
@@ -146,214 +134,158 @@ Args::GetQuotedCommandString (std::string &command) const
return argc > 0;
}
-void
-Args::SetCommandString (const char *command, size_t len)
+// A helper function for argument parsing.
+// Parses the initial part of the first argument using normal double quote rules:
+// backslash escapes the double quote and itself. The parsed string is appended to the second
+// argument. The function returns the unparsed portion of the string, starting at the closing
+// quote.
+static llvm::StringRef
+ParseDoubleQuotes(llvm::StringRef quoted, std::string &result)
{
- // Use std::string to make sure we get a NULL terminated string we can use
- // as "command" could point to a string within a large string....
- std::string null_terminated_command(command, len);
- SetCommandString(null_terminated_command.c_str());
+ // Inside double quotes, '\' and '"' are special.
+ static const char *k_escapable_characters = "\"\\";
+ while (true)
+ {
+ // Skip over over regular characters and append them.
+ size_t regular = quoted.find_first_of(k_escapable_characters);
+ result += quoted.substr(0, regular);
+ quoted = quoted.substr(regular);
+
+ // If we have reached the end of string or the closing quote, we're done.
+ if (quoted.empty() || quoted.front() == '"')
+ break;
+
+ // We have found a backslash.
+ quoted = quoted.drop_front();
+
+ if (quoted.empty())
+ {
+ // A lone backslash at the end of string, let's just append it.
+ result += '\\';
+ break;
+ }
+
+ // If the character after the backslash is not a whitelisted escapable character, we
+ // leave the character sequence untouched.
+ if (strchr(k_escapable_characters, quoted.front()) == nullptr)
+ result += '\\';
+
+ result += quoted.front();
+ quoted = quoted.drop_front();
+ }
+
+ return quoted;
}
-void
-Args::SetCommandString (const char *command)
+// A helper function for SetCommandString.
+// Parses a single argument from the command string, processing quotes and backslashes in a
+// shell-like manner. The parsed argument is appended to the m_args array. The function returns
+// the unparsed portion of the string, starting at the first unqouted, unescaped whitespace
+// character.
+llvm::StringRef
+Args::ParseSingleArgument(llvm::StringRef command)
{
- m_args.clear();
- m_argv.clear();
- m_args_quote_char.clear();
-
- if (command && command[0])
+ // Argument can be split into multiple discontiguous pieces,
+ // for example:
+ // "Hello ""World"
+ // this would result in a single argument "Hello World" (without/
+ // the quotes) since the quotes would be removed and there is
+ // not space between the strings.
+
+ std::string arg;
+
+ // Since we can have multiple quotes that form a single command
+ // in a command like: "Hello "world'!' (which will make a single
+ // argument "Hello world!") we remember the first quote character
+ // we encounter and use that for the quote character.
+ char first_quote_char = '\0';
+
+ bool arg_complete = false;
+ do
{
- static const char *k_space_separators = " \t";
- static const char *k_escapable_characters = " \t\\'\"";
- const char *arg_end = nullptr;
- const char *arg_pos;
- for (arg_pos = command;
- arg_pos && arg_pos[0];
- arg_pos = arg_end)
+ // Skip over over regular characters and append them.
+ size_t regular = command.find_first_of(" \t\"'`\\");
+ arg += command.substr(0, regular);
+ command = command.substr(regular);
+
+ if (command.empty())
+ break;
+
+ char special = command.front();
+ command = command.drop_front();
+ switch (special)
{
- // Skip any leading space separators
- const char *arg_start = ::strspn (arg_pos, k_space_separators) + arg_pos;
-
- // If there were only space separators to the end of the line, then
- // we're done.
- if (*arg_start == '\0')
+ case '\\':
+ if (command.empty())
+ {
+ arg += '\\';
break;
+ }
- // Arguments can be split into multiple discontiguous pieces,
- // for example:
- // "Hello ""World"
- // this would result in a single argument "Hello World" (without/
- // the quotes) since the quotes would be removed and there is
- // not space between the strings. So we need to keep track of the
- // current start of each argument piece in "arg_piece_start"
- const char *arg_piece_start = arg_start;
- arg_pos = arg_piece_start;
-
- std::string arg;
- // Since we can have multiple quotes that form a single command
- // in a command like: "Hello "world'!' (which will make a single
- // argument "Hello world!") we remember the first quote character
- // we encounter and use that for the quote character.
- char first_quote_char = '\0';
- char quote_char = '\0';
- bool arg_complete = false;
-
- do
- {
- arg_end = ::strcspn (arg_pos, k_escapable_characters) + arg_pos;
+ // If the character after the backslash is not a whitelisted escapable character, we
+ // leave the character sequence untouched.
+ if (strchr(" \t\\'\"`", command.front()) == nullptr)
+ arg += '\\';
- switch (arg_end[0])
- {
- default:
- assert (!"Unhandled case statement, we must handle this...");
- break;
+ arg += command.front();
+ command = command.drop_front();
- case '\0':
- // End of C string
- if (arg_piece_start && arg_piece_start[0])
- arg.append (arg_piece_start);
- arg_complete = true;
- break;
- case '\\':
- // Backslash character
- switch (arg_end[1])
- {
- case '\0':
- arg.append (arg_piece_start);
- ++arg_end;
- arg_complete = true;
- break;
-
- default:
- // Only consider this two-character sequence an escape sequence if we're unquoted and
- // the character after the backslash is a whitelisted escapable character. Otherwise
- // leave the character sequence untouched.
- if (quote_char == '\0' && (nullptr != strchr(k_escapable_characters, arg_end[1])))
- {
- arg.append (arg_piece_start, arg_end - arg_piece_start);
- arg.append (arg_end + 1, 1);
- arg_pos = arg_end + 2;
- arg_piece_start = arg_pos;
- }
- else
- arg_pos = arg_end + 2;
- break;
- }
- break;
- case '"':
- case '\'':
- case '`':
- // Quote characters
- if (quote_char)
- {
- // We found a quote character while inside a quoted
- // character argument. If it matches our current quote
- // character, this ends the effect of the quotes. If it
- // doesn't we ignore it.
- if (quote_char == arg_end[0])
- {
- arg.append (arg_piece_start, arg_end - arg_piece_start);
- // Clear the quote character and let parsing
- // continue (we need to watch for things like:
- // "Hello ""World"
- // "Hello "World
- // "Hello "'World'
- // All of which will result in a single argument "Hello World"
- quote_char = '\0'; // Note that we are no longer inside quotes
- arg_pos = arg_end + 1; // Skip the quote character
- arg_piece_start = arg_pos; // Note we are starting from later in the string
- }
- else
- {
- // different quote, skip it and keep going
- arg_pos = arg_end + 1;
- }
- }
- else
- {
- // We found the start of a quote scope.
- // Make sure there isn't a string that precedes
- // the start of a quote scope like:
- // Hello" World"
- // If so, then add the "Hello" to the arg
- if (arg_end > arg_piece_start)
- arg.append (arg_piece_start, arg_end - arg_piece_start);
-
- // Enter into a quote scope
- quote_char = arg_end[0];
-
- if (first_quote_char == '\0')
- first_quote_char = quote_char;
+ break;
- arg_pos = arg_end;
- ++arg_pos; // Skip the quote character
- arg_piece_start = arg_pos; // Note we are starting from later in the string
-
- // Skip till the next quote character
- const char *end_quote = ::strchr (arg_piece_start, quote_char);
- while (end_quote && end_quote[-1] == '\\')
- {
- // Don't skip the quote character if it is
- // preceded by a '\' character
- end_quote = ::strchr (end_quote + 1, quote_char);
- }
-
- if (end_quote)
- {
- if (end_quote > arg_piece_start)
- arg.append (arg_piece_start, end_quote - arg_piece_start);
+ case ' ':
+ case '\t':
+ // We are not inside any quotes, we just found a space after an
+ // argument. We are done.
+ arg_complete = true;
+ break;
- // If the next character is a space or the end of
- // string, this argument is complete...
- if (end_quote[1] == ' ' || end_quote[1] == '\t' || end_quote[1] == '\0')
- {
- arg_complete = true;
- arg_end = end_quote + 1;
- }
- else
- {
- arg_pos = end_quote + 1;
- arg_piece_start = arg_pos;
- }
- quote_char = '\0';
- }
- else
- {
- // Consume the rest of the string as there was no terminating quote
- arg.append(arg_piece_start);
- arg_end = arg_piece_start + strlen(arg_piece_start);
- arg_complete = true;
- }
- }
- break;
+ case '"':
+ case '\'':
+ case '`':
+ // We found the start of a quote scope.
+ if (first_quote_char == '\0')
+ first_quote_char = special;
- case ' ':
- case '\t':
- if (quote_char)
- {
- // We are currently processing a quoted character and found
- // a space character, skip any spaces and keep trying to find
- // the end of the argument.
- arg_pos = ::strspn (arg_end, k_space_separators) + arg_end;
- }
- else
- {
- // We are not inside any quotes, we just found a space after an
- // argument
- if (arg_end > arg_piece_start)
- arg.append (arg_piece_start, arg_end - arg_piece_start);
- arg_complete = true;
- }
- break;
- }
- } while (!arg_complete);
+ if (special == '"')
+ command = ParseDoubleQuotes(command, arg);
+ else
+ {
+ // For single quotes, we simply skip ahead to the matching quote character
+ // (or the end of the string).
+ size_t quoted = command.find(special);
+ arg += command.substr(0, quoted);
+ command = command.substr(quoted);
+ }
- m_args.push_back(arg);
- m_args_quote_char.push_back (first_quote_char);
+ // If we found a closing quote, skip it.
+ if (! command.empty())
+ command = command.drop_front();
+
+ break;
}
- UpdateArgvFromArgs();
+ } while (!arg_complete);
+
+ m_args.push_back(arg);
+ m_args_quote_char.push_back (first_quote_char);
+ return command;
+}
+
+void
+Args::SetCommandString (llvm::StringRef command)
+{
+ m_args.clear();
+ m_argv.clear();
+ m_args_quote_char.clear();
+
+ static const char *k_space_separators = " \t";
+ command = command.ltrim(k_space_separators);
+ while (!command.empty())
+ {
+ command = ParseSingleArgument(command);
+ command = command.ltrim(k_space_separators);
}
+
+ UpdateArgvFromArgs();
}
void
@@ -478,7 +410,8 @@ Args::AppendArguments (const Args &rhs)
{
const size_t rhs_argc = rhs.GetArgumentCount();
for (size_t i=0; i<rhs_argc; ++i)
- AppendArgument(rhs.GetArgumentAtIndex(i));
+ AppendArgument(rhs.GetArgumentAtIndex(i),
+ rhs.GetArgumentQuoteCharAtIndex(i));
}
void
@@ -870,26 +803,24 @@ Args::StripSpaces (std::string &s, bool leading, bool trailing, bool return_null
bool
Args::StringToBoolean (const char *s, bool fail_value, bool *success_ptr)
{
- if (s && s[0])
+ llvm::StringRef ref = llvm::StringRef(s).trim();
+ if (ref.equals_lower("false") ||
+ ref.equals_lower("off") ||
+ ref.equals_lower("no") ||
+ ref.equals_lower("0"))
{
- if (::strcasecmp (s, "false") == 0 ||
- ::strcasecmp (s, "off") == 0 ||
- ::strcasecmp (s, "no") == 0 ||
- ::strcmp (s, "0") == 0)
- {
- if (success_ptr)
- *success_ptr = true;
- return false;
- }
- else
- if (::strcasecmp (s, "true") == 0 ||
- ::strcasecmp (s, "on") == 0 ||
- ::strcasecmp (s, "yes") == 0 ||
- ::strcmp (s, "1") == 0)
- {
- if (success_ptr) *success_ptr = true;
- return true;
- }
+ if (success_ptr)
+ *success_ptr = true;
+ return false;
+ }
+ else
+ if (ref.equals_lower("true") ||
+ ref.equals_lower("on") ||
+ ref.equals_lower("yes") ||
+ ref.equals_lower("1"))
+ {
+ if (success_ptr) *success_ptr = true;
+ return true;
}
if (success_ptr) *success_ptr = false;
return fail_value;
@@ -1205,7 +1136,7 @@ Args::IsPositionalArgument (const char *arg)
return false;
bool is_positional = true;
- char *cptr = (char *) arg;
+ const char *cptr = arg;
if (cptr[0] == '%')
{
diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp
index 6318b80a29ed..1da541b8c00f 100644
--- a/source/Interpreter/CommandInterpreter.cpp
+++ b/source/Interpreter/CommandInterpreter.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include <string>
#include <vector>
#include <stdlib.h>
@@ -19,6 +17,7 @@
#include "../Commands/CommandObjectApropos.h"
#include "../Commands/CommandObjectArgs.h"
#include "../Commands/CommandObjectBreakpoint.h"
+#include "../Commands/CommandObjectBugreport.h"
#include "../Commands/CommandObjectDisassemble.h"
#include "../Commands/CommandObjectExpression.h"
#include "../Commands/CommandObjectFrame.h"
@@ -40,6 +39,7 @@
#include "../Commands/CommandObjectType.h"
#include "../Commands/CommandObjectVersion.h"
#include "../Commands/CommandObjectWatchpoint.h"
+#include "../Commands/CommandObjectLanguage.h"
#include "lldb/Core/Debugger.h"
@@ -60,6 +60,8 @@
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/Property.h"
#include "lldb/Interpreter/ScriptInterpreterNone.h"
#include "lldb/Interpreter/ScriptInterpreterPython.h"
@@ -77,6 +79,7 @@
using namespace lldb;
using namespace lldb_private;
+static const char *k_white_space = " \t\v";
static PropertyDefinition
g_properties[] =
@@ -107,7 +110,7 @@ CommandInterpreter::CommandInterpreter
ScriptLanguage script_language,
bool synchronous_execution
) :
- Broadcaster (&debugger, "lldb.command-interpreter"),
+ Broadcaster (&debugger, CommandInterpreter::GetStaticBroadcasterClass().AsCString()),
Properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter")))),
IOHandlerDelegate (IOHandlerDelegate::Completion::LLDBCommand),
m_debugger (debugger),
@@ -147,6 +150,24 @@ CommandInterpreter::GetPromptOnQuit () const
return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0);
}
+void
+CommandInterpreter::SetPromptOnQuit (bool b)
+{
+ const uint32_t idx = ePropertyPromptOnQuit;
+ m_collection_sp->SetPropertyAtIndexAsBoolean (nullptr, idx, b);
+}
+
+void
+CommandInterpreter::ResolveCommand(const char *command_line, CommandReturnObject &result)
+{
+ std::string command = command_line;
+ if (ResolveCommandImpl(command, result) != nullptr) {
+ result.AppendMessageWithFormat("%s", command.c_str());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+}
+
+
bool
CommandInterpreter::GetStopCmdSourceOnError () const
{
@@ -401,6 +422,7 @@ CommandInterpreter::LoadCommandDictionary ()
m_command_dict["apropos"] = CommandObjectSP (new CommandObjectApropos (*this));
m_command_dict["breakpoint"]= CommandObjectSP (new CommandObjectMultiwordBreakpoint (*this));
+ m_command_dict["bugreport"] = CommandObjectSP (new CommandObjectMultiwordBugreport (*this));
m_command_dict["command"] = CommandObjectSP (new CommandObjectMultiwordCommands (*this));
m_command_dict["disassemble"] = CommandObjectSP (new CommandObjectDisassemble (*this));
m_command_dict["expression"]= CommandObjectSP (new CommandObjectExpression (*this));
@@ -422,6 +444,7 @@ CommandInterpreter::LoadCommandDictionary ()
m_command_dict["type"] = CommandObjectSP (new CommandObjectType (*this));
m_command_dict["version"] = CommandObjectSP (new CommandObjectVersion (*this));
m_command_dict["watchpoint"]= CommandObjectSP (new CommandObjectMultiwordWatchpoint (*this));
+ m_command_dict["language"] = CommandObjectSP (new CommandObjectLanguage(*this));
const char *break_regexes[][2] = {{"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "breakpoint set --file '%1' --line %2"},
{"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
@@ -438,8 +461,14 @@ CommandInterpreter::LoadCommandDictionary ()
std::unique_ptr<CommandObjectRegexCommand>
break_regex_cmd_ap(new CommandObjectRegexCommand (*this,
"_regexp-break",
- "Set a breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.",
- "_regexp-break [<filename>:<linenum>]\n_regexp-break [<linenum>]\n_regexp-break [<address>]\n_regexp-break <...>",
+ "Set a breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.\n",
+ "\n_regexp-break <filename>:<linenum> # _regexp-break main.c:12 // Break on line 12 of main.c\n"
+ "_regexp-break <linenum> # _regexp-break 12 // Break on line 12 of current file\n"
+ "_regexp-break <address> # _regexp-break 0x1234000 // Break on address 0x1234000\n"
+ "_regexp-break <name> # _regexp-break main // Break in 'main' after the prologue\n"
+ "_regexp-break &<name> # _regexp-break &main // Break on the first instruction in 'main'\n"
+ "_regexp-break <module>`<name> # _regexp-break libc.so`malloc // Break in 'malloc' only in the 'libc.so' shared library\n"
+ "_regexp-break /<source-regex>/ # _regexp-break /break here/ // Break on all lines that match the regular expression 'break here' in the current file.\n",
2,
CommandCompletions::eSymbolCompletion |
CommandCompletions::eSourceFileCompletion,
@@ -1243,8 +1272,7 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string)
// eventually be invoked by the given command line.
CommandObject *cmd_obj = nullptr;
- std::string white_space (" \t\v");
- size_t start = command_string.find_first_not_of (white_space);
+ size_t start = command_string.find_first_not_of (k_white_space);
size_t end = 0;
bool done = false;
while (!done)
@@ -1252,7 +1280,7 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string)
if (start != std::string::npos)
{
// Get the next word from command_string.
- end = command_string.find_first_of (white_space, start);
+ end = command_string.find_first_of (k_white_space, start);
if (end == std::string::npos)
end = command_string.size();
std::string cmd_word = command_string.substr (start, end - start);
@@ -1267,7 +1295,7 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string)
CommandObject *sub_cmd_obj = cmd_obj->GetSubcommandObject (cmd_word.c_str());
if (sub_cmd_obj)
cmd_obj = sub_cmd_obj;
- else // cmd_word was not a valid sub-command word, so we are donee
+ else // cmd_word was not a valid sub-command word, so we are done
done = true;
}
else
@@ -1281,7 +1309,7 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string)
if (!cmd_obj || !cmd_obj->IsMultiwordObject() || end >= command_string.size())
done = true;
else
- start = command_string.find_first_not_of (white_space, end);
+ start = command_string.find_first_not_of (k_white_space, end);
}
else
// Unable to find any more words.
@@ -1296,7 +1324,6 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string)
return cmd_obj;
}
-static const char *k_white_space = " \t\v";
static const char *k_valid_command_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
static void
StripLeadingSpaces (std::string &s)
@@ -1412,7 +1439,7 @@ CommandInterpreter::BuildAliasResult (const char *alias_name,
CommandReturnObject &result)
{
CommandObject *alias_cmd_obj = nullptr;
- Args cmd_args (raw_input_string.c_str());
+ Args cmd_args (raw_input_string);
alias_cmd_obj = GetCommandObject (alias_name);
StreamString result_str;
@@ -1442,10 +1469,10 @@ CommandInterpreter::BuildAliasResult (const char *alias_name,
else
{
result_str.Printf (" %s", option.c_str());
- if (value_type != OptionParser::eOptionalArgument)
- result_str.Printf (" ");
- if (value.compare ("<OptionParser::eNoArgument>") != 0)
+ if (value_type != OptionParser::eNoArgument)
{
+ if (value_type != OptionParser::eOptionalArgument)
+ result_str.Printf (" ");
int index = GetOptionArgumentPosition (value.c_str());
if (index == 0)
result_str.Printf ("%s", value.c_str());
@@ -1456,7 +1483,7 @@ CommandInterpreter::BuildAliasResult (const char *alias_name,
("Not enough arguments provided; you need at least %d arguments to use this alias.\n",
index);
result.SetStatus (eReturnStatusFailed);
- return alias_cmd_obj;
+ return nullptr;
}
else
{
@@ -1481,7 +1508,7 @@ CommandInterpreter::PreprocessCommand (std::string &command)
{
// The command preprocessor needs to do things to the command
// line before any parsing of arguments or anything else is done.
- // The only current stuff that gets proprocessed is anyting enclosed
+ // The only current stuff that gets preprocessed is anything enclosed
// in backtick ('`') characters is evaluated as an expression and
// the result of the expression must be a scalar that can be substituted
// into the command. An example would be:
@@ -1493,7 +1520,7 @@ CommandInterpreter::PreprocessCommand (std::string &command)
{
if (start_backtick > 0 && command[start_backtick-1] == '\\')
{
- // The backtick was preceeded by a '\' character, remove the slash
+ // The backtick was preceded by a '\' character, remove the slash
// and don't treat the backtick as the start of an expression
command.erase(start_backtick-1, 1);
// No need to add one to start_backtick since we just deleted a char
@@ -1622,9 +1649,6 @@ CommandInterpreter::HandleCommand (const char *command_line,
{
- bool done = false;
- CommandObject *cmd_obj = nullptr;
- bool wants_raw_input = false;
std::string command_string (command_line);
std::string original_command_string (command_line);
@@ -1724,192 +1748,34 @@ CommandInterpreter::HandleCommand (const char *command_line,
result.SetStatus(eReturnStatusFailed);
return false;
}
- // Phase 1.
-
- // Before we do ANY kind of argument processing, etc. we need to figure out what the real/final command object
- // is for the specified command, and whether or not it wants raw input. This gets complicated by the fact that
- // the user could have specified an alias, and in translating the alias there may also be command options and/or
- // even data (including raw text strings) that need to be found and inserted into the command line as part of
- // the translation. So this first step is plain look-up & replacement, resulting in three things: 1). the command
- // object whose Execute method will actually be called; 2). a revised command string, with all substitutions &
- // replacements taken care of; 3). whether or not the Execute function wants raw input or not.
-
- StreamString revised_command_line;
- size_t actual_cmd_name_len = 0;
- std::string next_word;
- StringList matches;
- while (!done)
- {
- char quote_char = '\0';
- std::string suffix;
- ExtractCommand (command_string, next_word, suffix, quote_char);
- if (cmd_obj == nullptr)
- {
- std::string full_name;
- if (GetAliasFullName(next_word.c_str(), full_name))
- {
- std::string alias_result;
- cmd_obj = BuildAliasResult (full_name.c_str(), command_string, alias_result, result);
- revised_command_line.Printf ("%s", alias_result.c_str());
- if (cmd_obj)
- {
- wants_raw_input = cmd_obj->WantsRawCommandString ();
- actual_cmd_name_len = strlen (cmd_obj->GetCommandName());
- }
- }
- else
- {
- cmd_obj = GetCommandObject (next_word.c_str(), &matches);
- if (cmd_obj)
- {
- actual_cmd_name_len += next_word.length();
- revised_command_line.Printf ("%s", next_word.c_str());
- wants_raw_input = cmd_obj->WantsRawCommandString ();
- }
- else
- {
- revised_command_line.Printf ("%s", next_word.c_str());
- }
- }
- }
- else
- {
- if (cmd_obj->IsMultiwordObject ())
- {
- CommandObject *sub_cmd_obj = cmd_obj->GetSubcommandObject (next_word.c_str());
- if (sub_cmd_obj)
- {
- actual_cmd_name_len += next_word.length() + 1;
- revised_command_line.Printf (" %s", next_word.c_str());
- cmd_obj = sub_cmd_obj;
- wants_raw_input = cmd_obj->WantsRawCommandString ();
- }
- else
- {
- if (quote_char)
- revised_command_line.Printf (" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char);
- else
- revised_command_line.Printf (" %s%s", next_word.c_str(), suffix.c_str());
- done = true;
- }
- }
- else
- {
- if (quote_char)
- revised_command_line.Printf (" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char);
- else
- revised_command_line.Printf (" %s%s", next_word.c_str(), suffix.c_str());
- done = true;
- }
- }
-
- if (cmd_obj == nullptr)
- {
- const size_t num_matches = matches.GetSize();
- if (matches.GetSize() > 1) {
- StreamString error_msg;
- error_msg.Printf ("Ambiguous command '%s'. Possible matches:\n", next_word.c_str());
-
- for (uint32_t i = 0; i < num_matches; ++i) {
- error_msg.Printf ("\t%s\n", matches.GetStringAtIndex(i));
- }
- result.AppendRawError (error_msg.GetString().c_str());
- } else {
- // We didn't have only one match, otherwise we wouldn't get here.
- assert(num_matches == 0);
- result.AppendErrorWithFormat ("'%s' is not a valid command.\n", next_word.c_str());
- }
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- if (cmd_obj->IsMultiwordObject ())
- {
- if (!suffix.empty())
- {
-
- result.AppendErrorWithFormat ("command '%s' did not recognize '%s%s%s' as valid (subcommand might be invalid).\n",
- cmd_obj->GetCommandName(),
- next_word.empty() ? "" : next_word.c_str(),
- next_word.empty() ? " -- " : " ",
- suffix.c_str());
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- }
- else
- {
- // If we found a normal command, we are done
- done = true;
- if (!suffix.empty())
- {
- switch (suffix[0])
- {
- case '/':
- // GDB format suffixes
- {
- Options *command_options = cmd_obj->GetOptions();
- if (command_options && command_options->SupportsLongOption("gdb-format"))
- {
- std::string gdb_format_option ("--gdb-format=");
- gdb_format_option += (suffix.c_str() + 1);
+ // Phase 1.
- bool inserted = false;
- std::string &cmd = revised_command_line.GetString();
- size_t arg_terminator_idx = FindArgumentTerminator (cmd);
- if (arg_terminator_idx != std::string::npos)
- {
- // Insert the gdb format option before the "--" that terminates options
- gdb_format_option.append(1,' ');
- cmd.insert(arg_terminator_idx, gdb_format_option);
- inserted = true;
- }
+ // Before we do ANY kind of argument processing, we need to figure out what
+ // the real/final command object is for the specified command. This gets
+ // complicated by the fact that the user could have specified an alias, and,
+ // in translating the alias, there may also be command options and/or even
+ // data (including raw text strings) that need to be found and inserted into
+ // the command line as part of the translation. So this first step is plain
+ // look-up and replacement, resulting in:
+ // 1. the command object whose Execute method will actually be called
+ // 2. a revised command string, with all substitutions and replacements
+ // taken care of
+ // From 1 above, we can determine whether the Execute function wants raw
+ // input or not.
+
+ CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
+
+ // Although the user may have abbreviated the command, the command_string now
+ // has the command expanded to the full name. For example, if the input
+ // was "br s -n main", command_string is now "breakpoint set -n main".
- if (!inserted)
- revised_command_line.Printf (" %s", gdb_format_option.c_str());
-
- if (wants_raw_input && FindArgumentTerminator(cmd) == std::string::npos)
- revised_command_line.PutCString (" --");
- }
- else
- {
- result.AppendErrorWithFormat ("the '%s' command doesn't support the --gdb-format option\n",
- cmd_obj->GetCommandName());
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- }
- break;
-
- default:
- result.AppendErrorWithFormat ("unknown command shorthand suffix: '%s'\n",
- suffix.c_str());
- result.SetStatus (eReturnStatusFailed);
- return false;
-
- }
- }
- }
- if (command_string.length() == 0)
- done = true;
-
- }
-
- if (!command_string.empty())
- revised_command_line.Printf (" %s", command_string.c_str());
-
- // End of Phase 1.
- // At this point cmd_obj should contain the CommandObject whose Execute method will be called, if the command
- // specified was valid; revised_command_line contains the complete command line (including command name(s)),
- // fully translated with all substitutions & translations taken care of (still in raw text format); and
- // wants_raw_input specifies whether the Execute method expects raw input or not.
-
-
if (log)
{
- log->Printf ("HandleCommand, cmd_obj : '%s'", cmd_obj ? cmd_obj->GetCommandName() : "<not found>");
- log->Printf ("HandleCommand, revised_command_line: '%s'", revised_command_line.GetData());
- log->Printf ("HandleCommand, wants_raw_input:'%s'", wants_raw_input ? "True" : "False");
+ log->Printf("HandleCommand, cmd_obj : '%s'", cmd_obj ? cmd_obj->GetCommandName() : "<not found>");
+ log->Printf("HandleCommand, (revised) command_string: '%s'", command_string.c_str());
+ const bool wants_raw_input = (cmd_obj != NULL) ? cmd_obj->WantsRawCommandString() : false;
+ log->Printf("HandleCommand, wants_raw_input:'%s'", wants_raw_input ? "True" : "False");
}
// Phase 2.
@@ -1920,7 +1786,7 @@ CommandInterpreter::HandleCommand (const char *command_line,
{
if (add_to_history)
{
- Args command_args (revised_command_line.GetData());
+ Args command_args (command_string);
const char *repeat_command = cmd_obj->GetRepeatCommand(command_args, 0);
if (repeat_command != nullptr)
m_repeat_command.assign(repeat_command);
@@ -1930,18 +1796,13 @@ CommandInterpreter::HandleCommand (const char *command_line,
m_command_history.AppendString (original_command_string);
}
- command_string = revised_command_line.GetData();
- std::string command_name (cmd_obj->GetCommandName());
std::string remainder;
+ const std::size_t actual_cmd_name_len = strlen (cmd_obj->GetCommandName());
if (actual_cmd_name_len < command_string.length())
- remainder = command_string.substr (actual_cmd_name_len); // Note: 'actual_cmd_name_len' may be considerably shorter
- // than cmd_obj->GetCommandName(), because name completion
- // allows users to enter short versions of the names,
- // e.g. 'br s' for 'breakpoint set'.
+ remainder = command_string.substr (actual_cmd_name_len);
// Remove any initial spaces
- std::string white_space (" \t\v");
- size_t pos = remainder.find_first_not_of (white_space);
+ size_t pos = remainder.find_first_not_of (k_white_space);
if (pos != 0 && pos != std::string::npos)
remainder.erase(0, pos);
@@ -1953,7 +1814,7 @@ CommandInterpreter::HandleCommand (const char *command_line,
else
{
// We didn't find the first command object, so complete the first argument.
- Args command_args (revised_command_line.GetData());
+ Args command_args (command_string);
StringList matches;
int num_matches;
int cursor_index = 0;
@@ -2082,8 +1943,8 @@ CommandInterpreter::HandleCompletion (const char *current_line,
// We parse the argument up to the cursor, so the last argument in parsed_line is
// the one containing the cursor, and the cursor is after the last character.
- Args parsed_line(current_line, last_char - current_line);
- Args partial_parsed_line(current_line, cursor - current_line);
+ Args parsed_line(llvm::StringRef(current_line, last_char - current_line));
+ Args partial_parsed_line(llvm::StringRef(current_line, cursor - current_line));
// Don't complete comments, and if the line we are completing is just the history repeat character,
// substitute the appropriate history line.
@@ -2386,7 +2247,7 @@ CommandInterpreter::BuildAliasCommandArgs (CommandObject *alias_cmd_obj,
}
cmd_args.Clear();
- cmd_args.SetArguments (new_args.GetArgumentCount(), (const char **) new_args.GetArgumentVector());
+ cmd_args.SetArguments (new_args.GetArgumentCount(), new_args.GetConstArgumentVector());
}
else
{
@@ -2397,7 +2258,7 @@ CommandInterpreter::BuildAliasCommandArgs (CommandObject *alias_cmd_obj,
if (wants_raw_input)
{
cmd_args.Clear();
- cmd_args.SetArguments (new_args.GetArgumentCount(), (const char **) new_args.GetArgumentVector());
+ cmd_args.SetArguments (new_args.GetArgumentCount(), new_args.GetConstArgumentVector());
}
return;
}
@@ -2413,7 +2274,7 @@ CommandInterpreter::GetOptionArgumentPosition (const char *in_string)
int position = 0; // Any string that isn't an argument position, i.e. '%' followed by an integer, gets a position
// of zero.
- char *cptr = (char *) in_string;
+ const char *cptr = in_string;
// Does it start with '%'
if (cptr[0] == '%')
@@ -3355,7 +3216,7 @@ CommandInterpreter::RunCommandInterpreter(bool auto_handle_events,
bool spawn_thread,
CommandInterpreterRunOptions &options)
{
- // Always re-create the command intepreter when we run it in case
+ // Always re-create the command interpreter when we run it in case
// any file handles have changed.
bool force_create = true;
m_debugger.PushIOHandler(GetIOHandler(force_create, &options));
@@ -3370,7 +3231,7 @@ CommandInterpreter::RunCommandInterpreter(bool auto_handle_events,
}
else
{
- m_debugger.ExecuteIOHanders();
+ m_debugger.ExecuteIOHandlers();
if (auto_handle_events)
m_debugger.StopEventHandlerThread();
@@ -3378,3 +3239,179 @@ CommandInterpreter::RunCommandInterpreter(bool auto_handle_events,
}
+CommandObject *
+CommandInterpreter::ResolveCommandImpl(std::string &command_line, CommandReturnObject &result)
+{
+ std::string scratch_command(command_line); // working copy so we don't modify command_line unless we succeed
+ CommandObject *cmd_obj = nullptr;
+ StreamString revised_command_line;
+ bool wants_raw_input = false;
+ size_t actual_cmd_name_len = 0;
+ std::string next_word;
+ StringList matches;
+ bool done = false;
+ while (!done)
+ {
+ char quote_char = '\0';
+ std::string suffix;
+ ExtractCommand(scratch_command, next_word, suffix, quote_char);
+ if (cmd_obj == nullptr)
+ {
+ std::string full_name;
+ if (GetAliasFullName(next_word.c_str(), full_name))
+ {
+ std::string alias_result;
+ cmd_obj = BuildAliasResult(full_name.c_str(), scratch_command, alias_result, result);
+ revised_command_line.Printf("%s", alias_result.c_str());
+ if (cmd_obj)
+ {
+ wants_raw_input = cmd_obj->WantsRawCommandString();
+ actual_cmd_name_len = strlen(cmd_obj->GetCommandName());
+ }
+ }
+ else
+ {
+ cmd_obj = GetCommandObject(next_word.c_str(), &matches);
+ if (cmd_obj)
+ {
+ actual_cmd_name_len += strlen(cmd_obj->GetCommandName());
+ revised_command_line.Printf("%s", cmd_obj->GetCommandName());
+ wants_raw_input = cmd_obj->WantsRawCommandString();
+ }
+ else
+ {
+ revised_command_line.Printf ("%s", next_word.c_str());
+ }
+ }
+ }
+ else
+ {
+ if (cmd_obj->IsMultiwordObject ())
+ {
+ CommandObject *sub_cmd_obj = cmd_obj->GetSubcommandObject(next_word.c_str());
+ if (sub_cmd_obj)
+ {
+ // The subcommand's name includes the parent command's name,
+ // so restart rather than append to the revised_command_line.
+ actual_cmd_name_len = strlen(sub_cmd_obj->GetCommandName()) + 1;
+ revised_command_line.Clear();
+ revised_command_line.Printf("%s", sub_cmd_obj->GetCommandName());
+ cmd_obj = sub_cmd_obj;
+ wants_raw_input = cmd_obj->WantsRawCommandString();
+ }
+ else
+ {
+ if (quote_char)
+ revised_command_line.Printf(" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char);
+ else
+ revised_command_line.Printf(" %s%s", next_word.c_str(), suffix.c_str());
+ done = true;
+ }
+ }
+ else
+ {
+ if (quote_char)
+ revised_command_line.Printf(" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char);
+ else
+ revised_command_line.Printf(" %s%s", next_word.c_str(), suffix.c_str());
+ done = true;
+ }
+ }
+
+ if (cmd_obj == nullptr)
+ {
+ const size_t num_matches = matches.GetSize();
+ if (matches.GetSize() > 1) {
+ StreamString error_msg;
+ error_msg.Printf("Ambiguous command '%s'. Possible matches:\n", next_word.c_str());
+
+ for (uint32_t i = 0; i < num_matches; ++i) {
+ error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
+ }
+ result.AppendRawError(error_msg.GetString().c_str());
+ } else {
+ // We didn't have only one match, otherwise we wouldn't get here.
+ assert(num_matches == 0);
+ result.AppendErrorWithFormat("'%s' is not a valid command.\n", next_word.c_str());
+ }
+ result.SetStatus(eReturnStatusFailed);
+ return nullptr;
+ }
+
+ if (cmd_obj->IsMultiwordObject())
+ {
+ if (!suffix.empty())
+ {
+ result.AppendErrorWithFormat("command '%s' did not recognize '%s%s%s' as valid (subcommand might be invalid).\n",
+ cmd_obj->GetCommandName(),
+ next_word.empty() ? "" : next_word.c_str(),
+ next_word.empty() ? " -- " : " ",
+ suffix.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return nullptr;
+ }
+ }
+ else
+ {
+ // If we found a normal command, we are done
+ done = true;
+ if (!suffix.empty())
+ {
+ switch (suffix[0])
+ {
+ case '/':
+ // GDB format suffixes
+ {
+ Options *command_options = cmd_obj->GetOptions();
+ if (command_options && command_options->SupportsLongOption("gdb-format"))
+ {
+ std::string gdb_format_option("--gdb-format=");
+ gdb_format_option += (suffix.c_str() + 1);
+
+ bool inserted = false;
+ std::string &cmd = revised_command_line.GetString();
+ size_t arg_terminator_idx = FindArgumentTerminator(cmd);
+ if (arg_terminator_idx != std::string::npos)
+ {
+ // Insert the gdb format option before the "--" that terminates options
+ gdb_format_option.append(1,' ');
+ cmd.insert(arg_terminator_idx, gdb_format_option);
+ inserted = true;
+ }
+
+ if (!inserted)
+ revised_command_line.Printf(" %s", gdb_format_option.c_str());
+
+ if (wants_raw_input && FindArgumentTerminator(cmd) == std::string::npos)
+ revised_command_line.PutCString(" --");
+ }
+ else
+ {
+ result.AppendErrorWithFormat("the '%s' command doesn't support the --gdb-format option\n",
+ cmd_obj->GetCommandName());
+ result.SetStatus(eReturnStatusFailed);
+ return nullptr;
+ }
+ }
+ break;
+
+ default:
+ result.AppendErrorWithFormat("unknown command shorthand suffix: '%s'\n",
+ suffix.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return nullptr;
+ }
+ }
+ }
+ if (scratch_command.empty())
+ done = true;
+ }
+
+ if (!scratch_command.empty())
+ revised_command_line.Printf(" %s", scratch_command.c_str());
+
+ if (cmd_obj != NULL)
+ command_line = revised_command_line.GetData();
+
+ return cmd_obj;
+}
diff --git a/source/Interpreter/CommandObject.cpp b/source/Interpreter/CommandObject.cpp
index 753e720b0f6e..d67f76eba7b6 100644
--- a/source/Interpreter/CommandObject.cpp
+++ b/source/Interpreter/CommandObject.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/CommandObject.h"
#include <string>
@@ -25,13 +23,12 @@
// FIXME: Make a separate file for the completers.
#include "lldb/Host/FileSpec.h"
#include "lldb/Core/FileSpecList.h"
+#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
-#include "lldb/Interpreter/ScriptInterpreter.h"
-#include "lldb/Interpreter/ScriptInterpreterPython.h"
using namespace lldb;
using namespace lldb_private;
@@ -123,6 +120,12 @@ CommandObject::SetHelp (const char *cstr)
}
void
+CommandObject::SetHelp (std::string str)
+{
+ m_cmd_help_short = str;
+}
+
+void
CommandObject::SetHelpLong (const char *cstr)
{
m_cmd_help_long = cstr;
@@ -221,20 +224,20 @@ CommandObject::CheckRequirements (CommandReturnObject &result)
m_exe_ctx = m_interpreter.GetExecutionContext();
const uint32_t flags = GetFlags().Get();
- if (flags & (eFlagRequiresTarget |
- eFlagRequiresProcess |
- eFlagRequiresThread |
- eFlagRequiresFrame |
- eFlagTryTargetAPILock ))
+ if (flags & (eCommandRequiresTarget |
+ eCommandRequiresProcess |
+ eCommandRequiresThread |
+ eCommandRequiresFrame |
+ eCommandTryTargetAPILock ))
{
- if ((flags & eFlagRequiresTarget) && !m_exe_ctx.HasTargetScope())
+ if ((flags & eCommandRequiresTarget) && !m_exe_ctx.HasTargetScope())
{
result.AppendError (GetInvalidTargetDescription());
return false;
}
- if ((flags & eFlagRequiresProcess) && !m_exe_ctx.HasProcessScope())
+ if ((flags & eCommandRequiresProcess) && !m_exe_ctx.HasProcessScope())
{
if (!m_exe_ctx.HasTargetScope())
result.AppendError (GetInvalidTargetDescription());
@@ -243,7 +246,7 @@ CommandObject::CheckRequirements (CommandReturnObject &result)
return false;
}
- if ((flags & eFlagRequiresThread) && !m_exe_ctx.HasThreadScope())
+ if ((flags & eCommandRequiresThread) && !m_exe_ctx.HasThreadScope())
{
if (!m_exe_ctx.HasTargetScope())
result.AppendError (GetInvalidTargetDescription());
@@ -254,7 +257,7 @@ CommandObject::CheckRequirements (CommandReturnObject &result)
return false;
}
- if ((flags & eFlagRequiresFrame) && !m_exe_ctx.HasFrameScope())
+ if ((flags & eCommandRequiresFrame) && !m_exe_ctx.HasFrameScope())
{
if (!m_exe_ctx.HasTargetScope())
result.AppendError (GetInvalidTargetDescription());
@@ -267,13 +270,13 @@ CommandObject::CheckRequirements (CommandReturnObject &result)
return false;
}
- if ((flags & eFlagRequiresRegContext) && (m_exe_ctx.GetRegisterContext() == nullptr))
+ if ((flags & eCommandRequiresRegContext) && (m_exe_ctx.GetRegisterContext() == nullptr))
{
result.AppendError (GetInvalidRegContextDescription());
return false;
}
- if (flags & eFlagTryTargetAPILock)
+ if (flags & eCommandTryTargetAPILock)
{
Target *target = m_exe_ctx.GetTargetPtr();
if (target)
@@ -281,13 +284,13 @@ CommandObject::CheckRequirements (CommandReturnObject &result)
}
}
- if (GetFlags().AnySet (CommandObject::eFlagProcessMustBeLaunched | CommandObject::eFlagProcessMustBePaused))
+ if (GetFlags().AnySet (eCommandProcessMustBeLaunched | eCommandProcessMustBePaused))
{
Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
if (process == nullptr)
{
// A process that is not running is considered paused.
- if (GetFlags().Test(CommandObject::eFlagProcessMustBeLaunched))
+ if (GetFlags().Test(eCommandProcessMustBeLaunched))
{
result.AppendError ("Process must exist.");
result.SetStatus (eReturnStatusFailed);
@@ -311,7 +314,7 @@ CommandObject::CheckRequirements (CommandReturnObject &result)
case eStateDetached:
case eStateExited:
case eStateUnloaded:
- if (GetFlags().Test(CommandObject::eFlagProcessMustBeLaunched))
+ if (GetFlags().Test(eCommandProcessMustBeLaunched))
{
result.AppendError ("Process must be launched.");
result.SetStatus (eReturnStatusFailed);
@@ -321,7 +324,7 @@ CommandObject::CheckRequirements (CommandReturnObject &result)
case eStateRunning:
case eStateStepping:
- if (GetFlags().Test(CommandObject::eFlagProcessMustBePaused))
+ if (GetFlags().Test(eCommandProcessMustBePaused))
{
result.AppendError ("Process is running. Use 'process interrupt' to pause execution.");
result.SetStatus (eReturnStatusFailed);
@@ -499,14 +502,14 @@ CommandObject::GetArgumentEntryAtIndex (int idx)
return nullptr;
}
-CommandObject::ArgumentTableEntry *
+const CommandObject::ArgumentTableEntry *
CommandObject::FindArgumentDataByType (CommandArgumentType arg_type)
{
const ArgumentTableEntry *table = CommandObject::GetArgumentTable();
for (int i = 0; i < eArgTypeLastArg; ++i)
if (table[i].arg_type == arg_type)
- return (ArgumentTableEntry *) &(table[i]);
+ return &(table[i]);
return nullptr;
}
@@ -515,7 +518,7 @@ void
CommandObject::GetArgumentHelp (Stream &str, CommandArgumentType arg_type, CommandInterpreter &interpreter)
{
const ArgumentTableEntry* table = CommandObject::GetArgumentTable();
- ArgumentTableEntry *entry = (ArgumentTableEntry *) &(table[arg_type]);
+ const ArgumentTableEntry *entry = &(table[arg_type]);
// The table is *supposed* to be kept in arg_type order, but someone *could* have messed it up...
@@ -549,7 +552,7 @@ CommandObject::GetArgumentHelp (Stream &str, CommandArgumentType arg_type, Comma
const char *
CommandObject::GetArgumentName (CommandArgumentType arg_type)
{
- ArgumentTableEntry *entry = (ArgumentTableEntry *) &(CommandObject::GetArgumentTable()[arg_type]);
+ const ArgumentTableEntry *entry = &(CommandObject::GetArgumentTable()[arg_type]);
// The table is *supposed* to be kept in arg_type order, but someone *could* have messed it up...
@@ -843,12 +846,9 @@ LanguageTypeHelpTextCallback ()
StreamString sstr;
sstr << "One of the following languages:\n";
-
- for (unsigned int l = eLanguageTypeUnknown; l < eNumLanguageTypes; ++l)
- {
- sstr << " " << LanguageRuntime::GetNameForLanguageType(static_cast<LanguageType>(l)) << "\n";
- }
-
+
+ LanguageRuntime::PrintAllLanguages(sstr, " ", "\n");
+
sstr.Flush();
std::string data = sstr.GetString();
@@ -1020,18 +1020,15 @@ CommandObject::AddIDsArgumentData(CommandArgumentEntry &arg, CommandArgumentType
const char *
CommandObject::GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type)
{
- if (arg_type >=0 && arg_type < eArgTypeLastArg)
- return g_arguments_data[arg_type].arg_name;
- return nullptr;
-
+ assert(arg_type < eArgTypeLastArg && "Invalid argument type passed to GetArgumentTypeAsCString");
+ return g_arguments_data[arg_type].arg_name;
}
const char *
CommandObject::GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type)
{
- if (arg_type >=0 && arg_type < eArgTypeLastArg)
- return g_arguments_data[arg_type].help_text;
- return nullptr;
+ assert(arg_type < eArgTypeLastArg && "Invalid argument type passed to GetArgumentDescriptionAsCString");
+ return g_arguments_data[arg_type].help_text;
}
Target *
@@ -1192,6 +1189,7 @@ CommandObject::g_arguments_data[] =
{ 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." },
+ { eArgTypeTypeName, "type-name", CommandCompletions::eNoCompletion, { nullptr, false }, "A type 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." },
diff --git a/source/Interpreter/CommandObjectRegexCommand.cpp b/source/Interpreter/CommandObjectRegexCommand.cpp
index bde7f58b4cb0..1c3c3cdd5fdc 100644
--- a/source/Interpreter/CommandObjectRegexCommand.cpp
+++ b/source/Interpreter/CommandObjectRegexCommand.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/CommandObjectRegexCommand.h"
// C Includes
diff --git a/source/Interpreter/CommandObjectScript.cpp b/source/Interpreter/CommandObjectScript.cpp
index 9c67e4253301..31e5311ab441 100644
--- a/source/Interpreter/CommandObjectScript.cpp
+++ b/source/Interpreter/CommandObjectScript.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "CommandObjectScript.h"
// C Includes
diff --git a/source/Interpreter/OptionGroupBoolean.cpp b/source/Interpreter/OptionGroupBoolean.cpp
index 0c502cc364b4..6bd2743a6681 100644
--- a/source/Interpreter/OptionGroupBoolean.cpp
+++ b/source/Interpreter/OptionGroupBoolean.cpp
@@ -56,7 +56,7 @@ OptionGroupBoolean::SetOptionValue (CommandInterpreter &interpreter,
}
else
{
- error = m_value.SetValueFromCString (option_arg);
+ error = m_value.SetValueFromString (option_arg);
}
return error;
}
diff --git a/source/Interpreter/OptionGroupFile.cpp b/source/Interpreter/OptionGroupFile.cpp
index 9bfe8ddf0282..a4b56409698e 100644
--- a/source/Interpreter/OptionGroupFile.cpp
+++ b/source/Interpreter/OptionGroupFile.cpp
@@ -47,7 +47,7 @@ OptionGroupFile::SetOptionValue (CommandInterpreter &interpreter,
uint32_t option_idx,
const char *option_arg)
{
- Error error (m_file.SetValueFromCString (option_arg));
+ Error error (m_file.SetValueFromString (option_arg));
return error;
}
@@ -88,7 +88,7 @@ OptionGroupFileList::SetOptionValue (CommandInterpreter &interpreter,
uint32_t option_idx,
const char *option_arg)
{
- Error error (m_file_list.SetValueFromCString (option_arg));
+ Error error (m_file_list.SetValueFromString (option_arg));
return error;
}
diff --git a/source/Interpreter/OptionGroupFormat.cpp b/source/Interpreter/OptionGroupFormat.cpp
index 601a78458730..08ff262d5428 100644
--- a/source/Interpreter/OptionGroupFormat.cpp
+++ b/source/Interpreter/OptionGroupFormat.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/OptionGroupFormat.h"
// C Includes
@@ -78,7 +76,7 @@ OptionGroupFormat::SetOptionValue (CommandInterpreter &interpreter,
switch (short_option)
{
case 'f':
- error = m_format.SetValueFromCString (option_arg);
+ error = m_format.SetValueFromString (option_arg);
break;
case 'c':
@@ -88,7 +86,7 @@ OptionGroupFormat::SetOptionValue (CommandInterpreter &interpreter,
}
else
{
- error = m_count.SetValueFromCString (option_arg);
+ error = m_count.SetValueFromString (option_arg);
if (m_count.GetCurrentValue() == 0)
error.SetErrorStringWithFormat("invalid --count option value '%s'", option_arg);
}
@@ -101,7 +99,7 @@ OptionGroupFormat::SetOptionValue (CommandInterpreter &interpreter,
}
else
{
- error = m_byte_size.SetValueFromCString (option_arg);
+ error = m_byte_size.SetValueFromString (option_arg);
if (m_byte_size.GetCurrentValue() == 0)
error.SetErrorStringWithFormat("invalid --size option value '%s'", option_arg);
}
diff --git a/source/Interpreter/OptionGroupOutputFile.cpp b/source/Interpreter/OptionGroupOutputFile.cpp
index ec9e166d2f05..e95cd35976ec 100644
--- a/source/Interpreter/OptionGroupOutputFile.cpp
+++ b/source/Interpreter/OptionGroupOutputFile.cpp
@@ -36,7 +36,7 @@ g_option_table[] =
{ 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>'."},
+ "Append to the file specified with '--outfile <path>'."},
};
uint32_t
@@ -62,7 +62,7 @@ OptionGroupOutputFile::SetOptionValue (CommandInterpreter &interpreter,
switch (short_option)
{
case 'o':
- error = m_file.SetValueFromCString (option_arg);
+ error = m_file.SetValueFromString (option_arg);
break;
case SHORT_OPTION_APND:
diff --git a/source/Interpreter/OptionGroupPlatform.cpp b/source/Interpreter/OptionGroupPlatform.cpp
index 6bb36552d06b..6fa06d1eb8ed 100644
--- a/source/Interpreter/OptionGroupPlatform.cpp
+++ b/source/Interpreter/OptionGroupPlatform.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/OptionGroupPlatform.h"
// C Includes
diff --git a/source/Interpreter/OptionGroupString.cpp b/source/Interpreter/OptionGroupString.cpp
index 9bc1c94d3a5a..e0291b154be2 100644
--- a/source/Interpreter/OptionGroupString.cpp
+++ b/source/Interpreter/OptionGroupString.cpp
@@ -48,7 +48,7 @@ OptionGroupString::SetOptionValue (CommandInterpreter &interpreter,
uint32_t option_idx,
const char *option_arg)
{
- Error error (m_value.SetValueFromCString (option_arg));
+ Error error (m_value.SetValueFromString (option_arg));
return error;
}
diff --git a/source/Interpreter/OptionGroupUInt64.cpp b/source/Interpreter/OptionGroupUInt64.cpp
index 440c2a740c26..a922ab255968 100644
--- a/source/Interpreter/OptionGroupUInt64.cpp
+++ b/source/Interpreter/OptionGroupUInt64.cpp
@@ -48,7 +48,7 @@ OptionGroupUInt64::SetOptionValue (CommandInterpreter &interpreter,
uint32_t option_idx,
const char *option_arg)
{
- Error error (m_value.SetValueFromCString (option_arg));
+ Error error (m_value.SetValueFromString (option_arg));
return error;
}
diff --git a/source/Interpreter/OptionGroupUUID.cpp b/source/Interpreter/OptionGroupUUID.cpp
index 43f7386c9ca6..609967a83e79 100644
--- a/source/Interpreter/OptionGroupUUID.cpp
+++ b/source/Interpreter/OptionGroupUUID.cpp
@@ -56,7 +56,7 @@ OptionGroupUUID::SetOptionValue (CommandInterpreter &interpreter,
switch (short_option)
{
case 'u':
- error = m_uuid.SetValueFromCString (option_arg);
+ error = m_uuid.SetValueFromString (option_arg);
if (error.Success())
m_uuid.SetOptionWasSet();
break;
diff --git a/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/source/Interpreter/OptionGroupValueObjectDisplay.cpp
index 72d7ff597ab2..e5a5c004b2da 100644
--- a/source/Interpreter/OptionGroupValueObjectDisplay.cpp
+++ b/source/Interpreter/OptionGroupValueObjectDisplay.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
// C Includes
diff --git a/source/Interpreter/OptionGroupVariable.cpp b/source/Interpreter/OptionGroupVariable.cpp
index 05cf3f73bfed..092d60af9eb0 100644
--- a/source/Interpreter/OptionGroupVariable.cpp
+++ b/source/Interpreter/OptionGroupVariable.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/OptionGroupVariable.h"
// C Includes
diff --git a/source/Interpreter/OptionGroupWatchpoint.cpp b/source/Interpreter/OptionGroupWatchpoint.cpp
index f4d8df1e6ba7..c6f4b8f8c8ea 100644
--- a/source/Interpreter/OptionGroupWatchpoint.cpp
+++ b/source/Interpreter/OptionGroupWatchpoint.cpp
@@ -41,7 +41,7 @@ static OptionDefinition
g_option_table[] =
{
{ 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."}
+ { LLDB_OPT_SET_1, false, "size", 's', OptionParser::eRequiredArgument, nullptr, g_watch_size, 0, eArgTypeByteSize, "Number of bytes to use to watch a region."}
};
@@ -87,7 +87,7 @@ OptionGroupWatchpoint::SetOptionValue (CommandInterpreter &interpreter,
}
break;
}
- case 'x':
+ case 's':
watch_size = (uint32_t) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error);
break;
diff --git a/source/Interpreter/OptionValue.cpp b/source/Interpreter/OptionValue.cpp
index 1e4ea23cc075..8f136a5b1c57 100644
--- a/source/Interpreter/OptionValue.cpp
+++ b/source/Interpreter/OptionValue.cpp
@@ -222,6 +222,22 @@ OptionValue::GetAsFormat () const
return nullptr;
}
+OptionValueLanguage *
+OptionValue::GetAsLanguage ()
+{
+ if (GetType () == OptionValue::eTypeLanguage)
+ return static_cast<OptionValueLanguage *>(this);
+ return NULL;
+}
+
+const OptionValueLanguage *
+OptionValue::GetAsLanguage () const
+{
+ if (GetType () == OptionValue::eTypeLanguage)
+ return static_cast<const OptionValueLanguage *>(this);
+ return NULL;
+}
+
OptionValueFormatEntity *
OptionValue::GetAsFormatEntity ()
{
@@ -468,6 +484,27 @@ OptionValue::SetFormatValue (lldb::Format new_value)
return false;
}
+lldb::LanguageType
+OptionValue::GetLanguageValue (lldb::LanguageType fail_value) const
+{
+ const OptionValueLanguage *option_value = GetAsLanguage ();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return fail_value;
+}
+
+bool
+OptionValue::SetLanguageValue (lldb::LanguageType new_language)
+{
+ OptionValueLanguage *option_value = GetAsLanguage ();
+ if (option_value)
+ {
+ option_value->SetCurrentValue(new_language);
+ return true;
+ }
+ return false;
+}
+
const FormatEntity::Entry *
OptionValue::GetFormatEntity () const
{
@@ -589,6 +626,7 @@ OptionValue::GetBuiltinTypeAsCString (Type t)
case eTypeFileSpecList: return "file-list";
case eTypeFormat: return "format";
case eTypeFormatEntity: return "format-string";
+ case eTypeLanguage: return "language";
case eTypePathMap: return "path-map";
case eTypeProperties: return "properties";
case eTypeRegex: return "regex";
@@ -615,6 +653,7 @@ OptionValue::CreateValueFromCStringForTypeMask (const char *value_cstr, uint32_t
case 1u << eTypeFileSpec: value_sp.reset(new OptionValueFileSpec()); break;
case 1u << eTypeFormat: value_sp.reset(new OptionValueFormat(eFormatInvalid)); break;
case 1u << eTypeFormatEntity: value_sp.reset(new OptionValueFormatEntity(NULL)); break;
+ case 1u << eTypeLanguage: value_sp.reset(new OptionValueLanguage(eLanguageTypeUnknown)); break;
case 1u << eTypeSInt64: value_sp.reset(new OptionValueSInt64()); break;
case 1u << eTypeString: value_sp.reset(new OptionValueString()); break;
case 1u << eTypeUInt64: value_sp.reset(new OptionValueUInt64()); break;
@@ -622,7 +661,7 @@ OptionValue::CreateValueFromCStringForTypeMask (const char *value_cstr, uint32_t
}
if (value_sp)
- error = value_sp->SetValueFromCString (value_cstr, eVarSetOperationAssign);
+ error = value_sp->SetValueFromString (value_cstr, eVarSetOperationAssign);
else
error.SetErrorString("unsupported type mask");
return value_sp;
@@ -664,7 +703,7 @@ OptionValue::AutoComplete (CommandInterpreter &interpreter,
}
Error
-OptionValue::SetValueFromCString (const char *value, VarSetOperationType op)
+OptionValue::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
{
Error error;
switch (op)
diff --git a/source/Interpreter/OptionValueArch.cpp b/source/Interpreter/OptionValueArch.cpp
index 7df149234bda..0e1ca07afd2e 100644
--- a/source/Interpreter/OptionValueArch.cpp
+++ b/source/Interpreter/OptionValueArch.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/OptionValueArch.h"
// C Includes
@@ -43,7 +41,7 @@ OptionValueArch::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint3
}
Error
-OptionValueArch::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
+OptionValueArch::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
{
Error error;
switch (op)
@@ -55,28 +53,23 @@ OptionValueArch::SetValueFromCString (const char *value_cstr, VarSetOperationTyp
case eVarSetOperationReplace:
case eVarSetOperationAssign:
- if (value_cstr && value_cstr[0])
{
- if (m_current_value.SetTriple (value_cstr))
+ std::string value_str = value.trim().str();
+ if (m_current_value.SetTriple (value_str.c_str()))
{
m_value_was_set = true;
NotifyValueChanged();
}
else
- error.SetErrorStringWithFormat("unsupported architecture '%s'", value_cstr);
- }
- else
- {
- error.SetErrorString("invalid value string");
+ error.SetErrorStringWithFormat("unsupported architecture '%s'", value_str.c_str());
+ break;
}
- break;
-
case eVarSetOperationInsertBefore:
case eVarSetOperationInsertAfter:
case eVarSetOperationRemove:
case eVarSetOperationAppend:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value_cstr, op);
+ error = OptionValue::SetValueFromString (value, op);
break;
}
return error;
diff --git a/source/Interpreter/OptionValueArray.cpp b/source/Interpreter/OptionValueArray.cpp
index 86d49c9ba3b4..aabe457534d6 100644
--- a/source/Interpreter/OptionValueArray.cpp
+++ b/source/Interpreter/OptionValueArray.cpp
@@ -74,11 +74,13 @@ OptionValueArray::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint
}
Error
-OptionValueArray::SetValueFromCString (const char *value, VarSetOperationType op)
+OptionValueArray::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
{
- Args args(value);
- NotifyValueChanged();
- return SetArgs (args, op);
+ Args args(value.str().c_str());
+ Error error = SetArgs (args, op);
+ if (error.Success())
+ NotifyValueChanged();
+ return error;
}
@@ -342,6 +344,8 @@ OptionValueArray::DeepCopy () const
{
OptionValueArray *copied_array = new OptionValueArray (m_type_mask, m_raw_value_dump);
lldb::OptionValueSP copied_value_sp(copied_array);
+ *static_cast<OptionValue *>(copied_array) = *this;
+ copied_array->m_callback = m_callback;
const uint32_t size = m_values.size();
for (uint32_t i = 0; i<size; ++i)
{
diff --git a/source/Interpreter/OptionValueBoolean.cpp b/source/Interpreter/OptionValueBoolean.cpp
index 71cc2afb98e1..dae1f4b7a76d 100644
--- a/source/Interpreter/OptionValueBoolean.cpp
+++ b/source/Interpreter/OptionValueBoolean.cpp
@@ -37,7 +37,7 @@ OptionValueBoolean::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, ui
}
Error
-OptionValueBoolean::SetValueFromCString (const char *value_cstr,
+OptionValueBoolean::SetValueFromString (llvm::StringRef value_str,
VarSetOperationType op)
{
Error error;
@@ -52,7 +52,7 @@ OptionValueBoolean::SetValueFromCString (const char *value_cstr,
case eVarSetOperationAssign:
{
bool success = false;
- bool value = Args::StringToBoolean(value_cstr, false, &success);
+ bool value = Args::StringToBoolean(value_str.str().c_str(), false, &success);
if (success)
{
m_value_was_set = true;
@@ -61,12 +61,11 @@ OptionValueBoolean::SetValueFromCString (const char *value_cstr,
}
else
{
- if (value_cstr == nullptr)
- error.SetErrorString ("invalid boolean string value: NULL");
- else if (value_cstr[0] == '\0')
+ if (value_str.size() == 0)
error.SetErrorString ("invalid boolean string value <empty>");
else
- error.SetErrorStringWithFormat ("invalid boolean string value: '%s'", value_cstr);
+ error.SetErrorStringWithFormat ("invalid boolean string value: '%s'",
+ value_str.str().c_str());
}
}
break;
@@ -76,7 +75,7 @@ OptionValueBoolean::SetValueFromCString (const char *value_cstr,
case eVarSetOperationRemove:
case eVarSetOperationAppend:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value_cstr, op);
+ error = OptionValue::SetValueFromString (value_str, op);
break;
}
return error;
diff --git a/source/Interpreter/OptionValueChar.cpp b/source/Interpreter/OptionValueChar.cpp
index 7a0135314c81..b5ef1d346aea 100644
--- a/source/Interpreter/OptionValueChar.cpp
+++ b/source/Interpreter/OptionValueChar.cpp
@@ -39,7 +39,7 @@ OptionValueChar::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint3
}
Error
-OptionValueChar::SetValueFromCString (const char *value_cstr,
+OptionValueChar::SetValueFromString (llvm::StringRef value,
VarSetOperationType op)
{
Error error;
@@ -53,19 +53,19 @@ OptionValueChar::SetValueFromCString (const char *value_cstr,
case eVarSetOperationAssign:
{
bool success = false;
- char char_value = Args::StringToChar(value_cstr, '\0', &success);
+ char char_value = Args::StringToChar(value.str().c_str(), '\0', &success);
if (success)
{
m_current_value = char_value;
m_value_was_set = true;
}
else
- error.SetErrorStringWithFormat("'%s' cannot be longer than 1 character", value_cstr);
+ error.SetErrorStringWithFormat("'%s' cannot be longer than 1 character", value.str().c_str());
}
break;
default:
- error = OptionValue::SetValueFromCString (value_cstr, op);
+ error = OptionValue::SetValueFromString (value.str().c_str(), op);
break;
}
return error;
diff --git a/source/Interpreter/OptionValueDictionary.cpp b/source/Interpreter/OptionValueDictionary.cpp
index e5299f8cc390..24eeec3b3285 100644
--- a/source/Interpreter/OptionValueDictionary.cpp
+++ b/source/Interpreter/OptionValueDictionary.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/OptionValueDictionary.h"
// C Includes
@@ -119,6 +117,12 @@ OptionValueDictionary::SetArgs (const Args &args, VarSetOperationType op)
llvm::StringRef key_and_value(args.GetArgumentAtIndex(i));
if (!key_and_value.empty())
{
+ if (key_and_value.find('=') == llvm::StringRef::npos)
+ {
+ error.SetErrorString("assign operation takes one or more key=value arguments");
+ return error;
+ }
+
std::pair<llvm::StringRef, llvm::StringRef> kvp(key_and_value.split('='));
llvm::StringRef key = kvp.first;
bool key_valid = false;
@@ -126,7 +130,7 @@ OptionValueDictionary::SetArgs (const Args &args, VarSetOperationType op)
{
if (key.front() == '[')
{
- // Key name starts with '[', so the the key value must be in single or double quotes like:
+ // Key name starts with '[', so the key value must be in single or double quotes like:
// ['<key>']
// ["<key>"]
if ((key.size() > 2) && (key.back() == ']'))
@@ -211,16 +215,16 @@ OptionValueDictionary::SetArgs (const Args &args, VarSetOperationType op)
case eVarSetOperationInsertBefore:
case eVarSetOperationInsertAfter:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (nullptr, op);
+ error = OptionValue::SetValueFromString (llvm::StringRef(), op);
break;
}
return error;
}
Error
-OptionValueDictionary::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
+OptionValueDictionary::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
{
- Args args(value_cstr);
+ Args args(value.str().c_str());
Error error = SetArgs (args, op);
if (error.Success())
NotifyValueChanged();
@@ -320,7 +324,7 @@ OptionValueDictionary::GetSubValue (const ExecutionContext *exe_ctx, const char
}
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",
+ error.SetErrorStringWithFormat ("invalid value path '%s', %s values only support '[<key>]' subvalues where <key> a string value optionally delimited by single or double quotes",
name,
GetTypeAsCString());
}
@@ -335,7 +339,7 @@ OptionValueDictionary::SetSubValue (const ExecutionContext *exe_ctx, VarSetOpera
const bool will_modify = true;
lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, name, will_modify, error));
if (value_sp)
- error = value_sp->SetValueFromCString(value, op);
+ error = value_sp->SetValueFromString(value, op);
else
{
if (error.AsCString() == nullptr)
@@ -381,7 +385,7 @@ OptionValueDictionary::SetStringValueForKey (const ConstString &key,
return false;
if (pos->second->GetType() == OptionValue::eTypeString)
{
- pos->second->SetValueFromCString(value);
+ pos->second->SetValueFromString(value);
return true;
}
}
diff --git a/source/Interpreter/OptionValueEnumeration.cpp b/source/Interpreter/OptionValueEnumeration.cpp
index dbaeb185fa3a..0f163d1c4f74 100644
--- a/source/Interpreter/OptionValueEnumeration.cpp
+++ b/source/Interpreter/OptionValueEnumeration.cpp
@@ -55,7 +55,7 @@ OptionValueEnumeration::DumpValue (const ExecutionContext *exe_ctx, Stream &strm
}
Error
-OptionValueEnumeration::SetValueFromCString (const char *value, VarSetOperationType op)
+OptionValueEnumeration::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
{
Error error;
switch (op)
@@ -67,9 +67,8 @@ OptionValueEnumeration::SetValueFromCString (const char *value, VarSetOperationT
case eVarSetOperationReplace:
case eVarSetOperationAssign:
- if (value && value[0])
{
- ConstString const_enumerator_name(value);
+ ConstString const_enumerator_name(value.trim());
const EnumerationMapEntry *enumerator_entry = m_enumerations.FindFirstValueForName (const_enumerator_name.GetCString());
if (enumerator_entry)
{
@@ -79,7 +78,7 @@ OptionValueEnumeration::SetValueFromCString (const char *value, VarSetOperationT
else
{
StreamString error_strm;
- error_strm.Printf("invalid enumeration value '%s'", value);
+ error_strm.Printf("invalid enumeration value '%s'", value.str().c_str());
const size_t count = m_enumerations.GetSize ();
if (count)
{
@@ -91,19 +90,15 @@ OptionValueEnumeration::SetValueFromCString (const char *value, VarSetOperationT
}
error.SetErrorString(error_strm.GetData());
}
+ break;
}
- else
- {
- error.SetErrorString("invalid enumeration value");
- }
- break;
case eVarSetOperationInsertBefore:
case eVarSetOperationInsertAfter:
case eVarSetOperationRemove:
case eVarSetOperationAppend:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value, op);
+ error = OptionValue::SetValueFromString (value, op);
break;
}
return error;
diff --git a/source/Interpreter/OptionValueFileSpec.cpp b/source/Interpreter/OptionValueFileSpec.cpp
index 3f466985a83a..3a282f177fea 100644
--- a/source/Interpreter/OptionValueFileSpec.cpp
+++ b/source/Interpreter/OptionValueFileSpec.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/OptionValueFileSpec.h"
// C Includes
@@ -24,31 +22,39 @@ using namespace lldb;
using namespace lldb_private;
-OptionValueFileSpec::OptionValueFileSpec () :
+OptionValueFileSpec::OptionValueFileSpec (bool resolve) :
OptionValue(),
m_current_value (),
m_default_value (),
m_data_sp(),
- m_completion_mask (CommandCompletions::eDiskFileCompletion)
+ m_data_mod_time (),
+ m_completion_mask (CommandCompletions::eDiskFileCompletion),
+ m_resolve (resolve)
{
}
-OptionValueFileSpec::OptionValueFileSpec (const FileSpec &value) :
+OptionValueFileSpec::OptionValueFileSpec (const FileSpec &value,
+ bool resolve) :
OptionValue(),
m_current_value (value),
m_default_value (value),
m_data_sp(),
- m_completion_mask (CommandCompletions::eDiskFileCompletion)
+ m_data_mod_time (),
+ m_completion_mask (CommandCompletions::eDiskFileCompletion),
+ m_resolve (resolve)
{
}
OptionValueFileSpec::OptionValueFileSpec (const FileSpec &current_value,
- const FileSpec &default_value) :
+ const FileSpec &default_value,
+ bool resolve) :
OptionValue(),
m_current_value (current_value),
m_default_value (default_value),
m_data_sp(),
- m_completion_mask (CommandCompletions::eDiskFileCompletion)
+ m_data_mod_time (),
+ m_completion_mask (CommandCompletions::eDiskFileCompletion),
+ m_resolve (resolve)
{
}
@@ -70,7 +76,7 @@ OptionValueFileSpec::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, u
}
Error
-OptionValueFileSpec::SetValueFromCString (const char *value_cstr,
+OptionValueFileSpec::SetValueFromString (llvm::StringRef value,
VarSetOperationType op)
{
Error error;
@@ -83,24 +89,18 @@ OptionValueFileSpec::SetValueFromCString (const char *value_cstr,
case eVarSetOperationReplace:
case eVarSetOperationAssign:
- if (value_cstr && value_cstr[0])
+ if (value.size() > 0)
{
// The setting value may have whitespace, double-quotes, or single-quotes around the file
// path to indicate that internal spaces are not word breaks. Strip off any ws & quotes
// from the start and end of the file path - we aren't doing any word // breaking here so
// the quoting is unnecessary. NB this will cause a problem if someone tries to specify
// a file path that legitimately begins or ends with a " or ' character, or whitespace.
- std::string filepath(value_cstr);
- auto prefix_chars_to_trim = filepath.find_first_not_of ("\"' \t");
- if (prefix_chars_to_trim != std::string::npos && prefix_chars_to_trim > 0)
- filepath.erase(0, prefix_chars_to_trim);
- auto suffix_chars_to_trim = filepath.find_last_not_of ("\"' \t");
- if (suffix_chars_to_trim != std::string::npos && suffix_chars_to_trim < filepath.size())
- filepath.erase (suffix_chars_to_trim + 1);
-
+ value = value.trim("\"' \t");
m_value_was_set = true;
- m_current_value.SetFile(filepath.c_str(), true);
+ m_current_value.SetFile(value.str().c_str(), m_resolve);
m_data_sp.reset();
+ m_data_mod_time.Clear();
NotifyValueChanged();
}
else
@@ -114,7 +114,7 @@ OptionValueFileSpec::SetValueFromCString (const char *value_cstr,
case eVarSetOperationRemove:
case eVarSetOperationAppend:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value_cstr, op);
+ error = OptionValue::SetValueFromString (value, op);
break;
}
return error;
@@ -153,12 +153,16 @@ OptionValueFileSpec::AutoComplete (CommandInterpreter &interpreter,
const lldb::DataBufferSP &
OptionValueFileSpec::GetFileContents(bool null_terminate)
{
- if (!m_data_sp && m_current_value)
+ if (m_current_value)
{
+ const TimeValue file_mod_time = m_current_value.GetModificationTime();
+ if (m_data_sp && m_data_mod_time == file_mod_time)
+ return m_data_sp;
if (null_terminate)
m_data_sp = m_current_value.ReadFileContentsAsCString();
else
m_data_sp = m_current_value.ReadFileContents();
+ m_data_mod_time = file_mod_time;
}
return m_data_sp;
}
diff --git a/source/Interpreter/OptionValueFileSpecLIst.cpp b/source/Interpreter/OptionValueFileSpecLIst.cpp
index 0e696ca91db6..669d3ee33acc 100644
--- a/source/Interpreter/OptionValueFileSpecLIst.cpp
+++ b/source/Interpreter/OptionValueFileSpecLIst.cpp
@@ -42,10 +42,10 @@ OptionValueFileSpecList::DumpValue (const ExecutionContext *exe_ctx, Stream &str
}
Error
-OptionValueFileSpecList::SetValueFromCString (const char *value, VarSetOperationType op)
+OptionValueFileSpecList::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
{
Error error;
- Args args(value);
+ Args args(value.str().c_str());
const size_t argc = args.GetArgumentCount();
switch (op)
@@ -174,7 +174,7 @@ OptionValueFileSpecList::SetValueFromCString (const char *value, VarSetOperation
break;
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value, op);
+ error = OptionValue::SetValueFromString (value, op);
break;
}
return error;
diff --git a/source/Interpreter/OptionValueFormat.cpp b/source/Interpreter/OptionValueFormat.cpp
index d91f10b0edeb..1d73d58ce8e1 100644
--- a/source/Interpreter/OptionValueFormat.cpp
+++ b/source/Interpreter/OptionValueFormat.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/OptionValueFormat.h"
// C Includes
@@ -36,7 +34,7 @@ OptionValueFormat::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uin
}
Error
-OptionValueFormat::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
+OptionValueFormat::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
{
Error error;
switch (op)
@@ -50,7 +48,7 @@ OptionValueFormat::SetValueFromCString (const char *value_cstr, VarSetOperationT
case eVarSetOperationAssign:
{
Format new_format;
- error = Args::StringToFormat (value_cstr, new_format, nullptr);
+ error = Args::StringToFormat (value.str().c_str(), new_format, nullptr);
if (error.Success())
{
m_value_was_set = true;
@@ -65,7 +63,7 @@ OptionValueFormat::SetValueFromCString (const char *value_cstr, VarSetOperationT
case eVarSetOperationRemove:
case eVarSetOperationAppend:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value_cstr, op);
+ error = OptionValue::SetValueFromString (value, op);
break;
}
return error;
diff --git a/source/Interpreter/OptionValueFormatEntity.cpp b/source/Interpreter/OptionValueFormatEntity.cpp
index fb8c682a03f8..66d8d8419ed8 100644
--- a/source/Interpreter/OptionValueFormatEntity.cpp
+++ b/source/Interpreter/OptionValueFormatEntity.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/OptionValueFormatEntity.h"
// C Includes
@@ -67,8 +65,8 @@ OptionValueFormatEntity::DumpValue (const ExecutionContext *exe_ctx, Stream &str
}
Error
-OptionValueFormatEntity::SetValueFromCString (const char *value_cstr,
- VarSetOperationType op)
+OptionValueFormatEntity::SetValueFromString (llvm::StringRef value_str,
+ VarSetOperationType op)
{
Error error;
switch (op)
@@ -81,13 +79,31 @@ OptionValueFormatEntity::SetValueFromCString (const char *value_cstr,
case eVarSetOperationReplace:
case eVarSetOperationAssign:
{
+ // Check if the string starts with a quote character after removing leading and trailing spaces.
+ // If it does start with a quote character, make sure it ends with the same quote character
+ // and remove the quotes before we parse the format string. If the string doesn't start with
+ // a quote, leave the string alone and parse as is.
+ llvm::StringRef trimmed_value_str = value_str.trim();
+ if (!trimmed_value_str.empty())
+ {
+ const char first_char = trimmed_value_str[0];
+ if (first_char == '"' || first_char == '\'')
+ {
+ const size_t trimmed_len = trimmed_value_str.size();
+ if (trimmed_len == 1 || value_str[trimmed_len-1] != first_char)
+ {
+ error.SetErrorStringWithFormat("mismatched quotes");
+ return error;
+ }
+ value_str = trimmed_value_str.substr(1,trimmed_len-2);
+ }
+ }
FormatEntity::Entry entry;
- llvm::StringRef value_str(value_cstr);
error = FormatEntity::Parse(value_str, entry);
if (error.Success())
{
m_current_entry = std::move(entry);
- m_current_format = value_cstr;
+ m_current_format = value_str;
m_value_was_set = true;
NotifyValueChanged();
}
@@ -99,7 +115,7 @@ OptionValueFormatEntity::SetValueFromCString (const char *value_cstr,
case eVarSetOperationRemove:
case eVarSetOperationAppend:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value_cstr, op);
+ error = OptionValue::SetValueFromString (value_str, op);
break;
}
return error;
diff --git a/source/Interpreter/OptionValueLanguage.cpp b/source/Interpreter/OptionValueLanguage.cpp
new file mode 100644
index 000000000000..fd46553dabde
--- /dev/null
+++ b/source/Interpreter/OptionValueLanguage.cpp
@@ -0,0 +1,73 @@
+//===-- OptionValueFormat.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/OptionValueLanguage.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Target/LanguageRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueLanguage::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
+{
+ if (dump_mask & eDumpOptionType)
+ strm.Printf ("(%s)", GetTypeAsCString ());
+ if (dump_mask & eDumpOptionValue)
+ {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString (" = ");
+ strm.PutCString (LanguageRuntime::GetNameForLanguageType(m_current_value));
+ }
+}
+
+Error
+OptionValueLanguage::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
+{
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ {
+ LanguageType new_type = LanguageRuntime::GetLanguageTypeFromString(value.data());
+ m_value_was_set = true;
+ m_current_value = new_type;
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+ return error;
+}
+
+
+lldb::OptionValueSP
+OptionValueLanguage::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueLanguage(*this));
+}
+
diff --git a/source/Interpreter/OptionValuePathMappings.cpp b/source/Interpreter/OptionValuePathMappings.cpp
index b1e714e97073..722d6a144279 100644
--- a/source/Interpreter/OptionValuePathMappings.cpp
+++ b/source/Interpreter/OptionValuePathMappings.cpp
@@ -34,10 +34,10 @@ OptionValuePathMappings::DumpValue (const ExecutionContext *exe_ctx, Stream &str
}
Error
-OptionValuePathMappings::SetValueFromCString (const char *value, VarSetOperationType op)
+OptionValuePathMappings::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
{
Error error;
- Args args(value);
+ Args args(value.str().c_str());
const size_t argc = args.GetArgumentCount();
switch (op)
@@ -175,7 +175,7 @@ OptionValuePathMappings::SetValueFromCString (const char *value, VarSetOperation
break;
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value, op);
+ error = OptionValue::SetValueFromString (value, op);
break;
}
return error;
diff --git a/source/Interpreter/OptionValueProperties.cpp b/source/Interpreter/OptionValueProperties.cpp
index cf7abaa6ac25..e8d870a99cf8 100644
--- a/source/Interpreter/OptionValueProperties.cpp
+++ b/source/Interpreter/OptionValueProperties.cpp
@@ -226,7 +226,7 @@ OptionValueProperties::SetSubValue (const ExecutionContext *exe_ctx,
const bool will_modify = true;
lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, name, will_modify, error));
if (value_sp)
- error = value_sp->SetValueFromCString(value, op);
+ error = value_sp->SetValueFromString(value ? llvm::StringRef(value) : llvm::StringRef(), op);
else
{
if (error.AsCString() == nullptr)
@@ -600,7 +600,7 @@ OptionValueProperties::Clear ()
Error
-OptionValueProperties::SetValueFromCString (const char *value, VarSetOperationType op)
+OptionValueProperties::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
{
Error error;
@@ -619,7 +619,7 @@ OptionValueProperties::SetValueFromCString (const char *value, VarSetOperationTy
case eVarSetOperationInsertAfter:
case eVarSetOperationAppend:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value, op);
+ error = OptionValue::SetValueFromString (value, op);
break;
}
diff --git a/source/Interpreter/OptionValueRegex.cpp b/source/Interpreter/OptionValueRegex.cpp
index fab462f0e704..ebe7ae2feb91 100644
--- a/source/Interpreter/OptionValueRegex.cpp
+++ b/source/Interpreter/OptionValueRegex.cpp
@@ -41,7 +41,7 @@ OptionValueRegex::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint
}
Error
-OptionValueRegex::SetValueFromCString (const char *value_cstr,
+OptionValueRegex::SetValueFromString (llvm::StringRef value,
VarSetOperationType op)
{
Error error;
@@ -52,7 +52,7 @@ OptionValueRegex::SetValueFromCString (const char *value_cstr,
case eVarSetOperationInsertAfter:
case eVarSetOperationRemove:
case eVarSetOperationAppend:
- error = OptionValue::SetValueFromCString (value_cstr, op);
+ error = OptionValue::SetValueFromString (value, op);
break;
case eVarSetOperationClear:
@@ -62,7 +62,7 @@ OptionValueRegex::SetValueFromCString (const char *value_cstr,
case eVarSetOperationReplace:
case eVarSetOperationAssign:
- if (m_regex.Compile (value_cstr))
+ if (m_regex.Compile (value.str().c_str()))
{
m_value_was_set = true;
NotifyValueChanged();
diff --git a/source/Interpreter/OptionValueSInt64.cpp b/source/Interpreter/OptionValueSInt64.cpp
index c69172921a6d..97cdf10b7c75 100644
--- a/source/Interpreter/OptionValueSInt64.cpp
+++ b/source/Interpreter/OptionValueSInt64.cpp
@@ -36,9 +36,8 @@ OptionValueSInt64::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uin
}
Error
-OptionValueSInt64::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
+OptionValueSInt64::SetValueFromString (llvm::StringRef value_ref, VarSetOperationType op)
{
- //printf ("%p: SetValueFromCString (s=\"%s\", op=%i)\n", this, value_cstr, op);
Error error;
switch (op)
{
@@ -51,7 +50,8 @@ OptionValueSInt64::SetValueFromCString (const char *value_cstr, VarSetOperationT
case eVarSetOperationAssign:
{
bool success = false;
- int64_t value = StringConvert::ToSInt64 (value_cstr, 0, 0, &success);
+ std::string value_str = value_ref.trim().str();
+ int64_t value = StringConvert::ToSInt64 (value_str.c_str(), 0, 0, &success);
if (success)
{
if (value >= m_min_value && value <= m_max_value)
@@ -68,7 +68,8 @@ OptionValueSInt64::SetValueFromCString (const char *value_cstr, VarSetOperationT
}
else
{
- error.SetErrorStringWithFormat ("invalid int64_t string value: '%s'", value_cstr);
+ error.SetErrorStringWithFormat ("invalid int64_t string value: '%s'",
+ value_ref.str().c_str());
}
}
break;
@@ -78,7 +79,7 @@ OptionValueSInt64::SetValueFromCString (const char *value_cstr, VarSetOperationT
case eVarSetOperationRemove:
case eVarSetOperationAppend:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value_cstr, op);
+ error = OptionValue::SetValueFromString (value_ref, op);
break;
}
return error;
diff --git a/source/Interpreter/OptionValueString.cpp b/source/Interpreter/OptionValueString.cpp
index a1b80d8fc4f6..63f006e643f9 100644
--- a/source/Interpreter/OptionValueString.cpp
+++ b/source/Interpreter/OptionValueString.cpp
@@ -51,30 +51,30 @@ OptionValueString::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uin
}
Error
-OptionValueString::SetValueFromCString (const char *value_cstr,
+OptionValueString::SetValueFromString (llvm::StringRef value,
VarSetOperationType op)
{
Error error;
- std::string value_str_no_quotes;
- if (value_cstr)
+ std::string value_str = value.str();
+ value = value.trim();
+ if (value.size() > 0)
{
- switch (value_cstr[0])
+ switch (value.front())
{
case '"':
case '\'':
{
- size_t len = strlen(value_cstr);
- if (len <= 1 || value_cstr[len-1] != value_cstr[0])
+ if (value.size() <= 1 || value.back() != value.front())
{
error.SetErrorString("mismatched quotes");
return error;
}
- value_str_no_quotes.assign (value_cstr + 1, len - 2);
- value_cstr = value_str_no_quotes.c_str();
+ value = value.drop_front().drop_back();
}
break;
}
+ value_str = value.str();
}
switch (op)
@@ -85,26 +85,26 @@ OptionValueString::SetValueFromCString (const char *value_cstr,
case eVarSetOperationRemove:
if (m_validator)
{
- error = m_validator(value_cstr,m_validator_baton);
+ error = m_validator(value_str.c_str(),m_validator_baton);
if (error.Fail())
return error;
}
- error = OptionValue::SetValueFromCString (value_cstr, op);
+ error = OptionValue::SetValueFromString (value, op);
break;
case eVarSetOperationAppend:
{
std::string new_value(m_current_value);
- if (value_cstr && value_cstr[0])
+ if (value.size() > 0)
{
if (m_options.Test (eOptionEncodeCharacterEscapeSequences))
{
std::string str;
- Args::EncodeEscapeSequences (value_cstr, str);
+ Args::EncodeEscapeSequences (value_str.c_str(), str);
new_value.append(str);
}
else
- new_value.append(value_cstr);
+ new_value.append(value);
}
if (m_validator)
{
@@ -126,18 +126,18 @@ OptionValueString::SetValueFromCString (const char *value_cstr,
case eVarSetOperationAssign:
if (m_validator)
{
- error = m_validator(value_cstr,m_validator_baton);
+ error = m_validator(value_str.c_str(), m_validator_baton);
if (error.Fail())
return error;
}
m_value_was_set = true;
if (m_options.Test (eOptionEncodeCharacterEscapeSequences))
{
- Args::EncodeEscapeSequences (value_cstr, m_current_value);
+ Args::EncodeEscapeSequences (value_str.c_str(), m_current_value);
}
else
{
- SetCurrentValue (value_cstr);
+ SetCurrentValue (value_str.c_str());
}
NotifyValueChanged();
break;
diff --git a/source/Interpreter/OptionValueUInt64.cpp b/source/Interpreter/OptionValueUInt64.cpp
index 48de433d36c1..b414802b963b 100644
--- a/source/Interpreter/OptionValueUInt64.cpp
+++ b/source/Interpreter/OptionValueUInt64.cpp
@@ -23,7 +23,7 @@ lldb::OptionValueSP
OptionValueUInt64::Create (const char *value_cstr, Error &error)
{
lldb::OptionValueSP value_sp (new OptionValueUInt64());
- error = value_sp->SetValueFromCString (value_cstr);
+ error = value_sp->SetValueFromString (value_cstr);
if (error.Fail())
value_sp.reset();
return value_sp;
@@ -44,7 +44,7 @@ OptionValueUInt64::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uin
}
Error
-OptionValueUInt64::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
+OptionValueUInt64::SetValueFromString (llvm::StringRef value_ref, VarSetOperationType op)
{
Error error;
switch (op)
@@ -58,7 +58,8 @@ OptionValueUInt64::SetValueFromCString (const char *value_cstr, VarSetOperationT
case eVarSetOperationAssign:
{
bool success = false;
- uint64_t value = StringConvert::ToUInt64 (value_cstr, 0, 0, &success);
+ std::string value_str = value_ref.trim().str();
+ uint64_t value = StringConvert::ToUInt64 (value_str.c_str(), 0, 0, &success);
if (success)
{
m_value_was_set = true;
@@ -67,7 +68,7 @@ OptionValueUInt64::SetValueFromCString (const char *value_cstr, VarSetOperationT
}
else
{
- error.SetErrorStringWithFormat ("invalid uint64_t string value: '%s'", value_cstr);
+ error.SetErrorStringWithFormat ("invalid uint64_t string value: '%s'", value_str.c_str());
}
}
break;
@@ -77,7 +78,7 @@ OptionValueUInt64::SetValueFromCString (const char *value_cstr, VarSetOperationT
case eVarSetOperationRemove:
case eVarSetOperationAppend:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value_cstr, op);
+ error = OptionValue::SetValueFromString (value_ref, op);
break;
}
return error;
diff --git a/source/Interpreter/OptionValueUUID.cpp b/source/Interpreter/OptionValueUUID.cpp
index c228cf6e415e..b16a9eb7e994 100644
--- a/source/Interpreter/OptionValueUUID.cpp
+++ b/source/Interpreter/OptionValueUUID.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/OptionValueUUID.h"
// C Includes
@@ -37,7 +35,7 @@ OptionValueUUID::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint3
}
Error
-OptionValueUUID::SetValueFromCString (const char *value_cstr,
+OptionValueUUID::SetValueFromString (llvm::StringRef value,
VarSetOperationType op)
{
Error error;
@@ -51,8 +49,8 @@ OptionValueUUID::SetValueFromCString (const char *value_cstr,
case eVarSetOperationReplace:
case eVarSetOperationAssign:
{
- if (m_uuid.SetFromCString(value_cstr) == 0)
- error.SetErrorStringWithFormat ("invalid uuid string value '%s'", value_cstr);
+ if (m_uuid.SetFromCString(value.str().c_str()) == 0)
+ error.SetErrorStringWithFormat ("invalid uuid string value '%s'", value.str().c_str());
else
{
m_value_was_set = true;
@@ -66,7 +64,7 @@ OptionValueUUID::SetValueFromCString (const char *value_cstr,
case eVarSetOperationRemove:
case eVarSetOperationAppend:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (value_cstr, op);
+ error = OptionValue::SetValueFromString (value, op);
break;
}
return error;
diff --git a/source/Interpreter/Options.cpp b/source/Interpreter/Options.cpp
index a8766f5f8615..7f0e0abc03ea 100644
--- a/source/Interpreter/Options.cpp
+++ b/source/Interpreter/Options.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/Options.h"
// C Includes
@@ -944,7 +942,7 @@ Options::HandleOptionArgumentCompletion
lldb::CommandArgumentType option_arg_type = opt_defs[opt_defs_index].argument_type;
if (option_arg_type != eArgTypeNone)
{
- CommandObject::ArgumentTableEntry *arg_entry = CommandObject::FindArgumentDataByType (opt_defs[opt_defs_index].argument_type);
+ const CommandObject::ArgumentTableEntry *arg_entry = CommandObject::FindArgumentDataByType (opt_defs[opt_defs_index].argument_type);
if (arg_entry)
completion_mask = arg_entry->completion_type;
}
diff --git a/source/Interpreter/Property.cpp b/source/Interpreter/Property.cpp
index 5679ef8dd3ba..077fcbc54cc3 100644
--- a/source/Interpreter/Property.cpp
+++ b/source/Interpreter/Property.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/Property.h"
// C Includes
@@ -19,6 +17,7 @@
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/OptionValues.h"
+#include "lldb/Target/LanguageRuntime.h"
using namespace lldb;
using namespace lldb_private;
@@ -80,11 +79,11 @@ Property::Property (const PropertyDefinition &definition) :
m_value_sp.reset (enum_value);
if (definition.default_cstr_value)
{
- if (enum_value->SetValueFromCString(definition.default_cstr_value).Success())
+ if (enum_value->SetValueFromString(definition.default_cstr_value).Success())
{
enum_value->SetDefaultValue(enum_value->GetCurrentValue());
// Call Clear() since we don't want the value to appear as
- // having been set since we called SetValueFromCString() above.
+ // having been set since we called SetValueFromString() above.
// Clear will set the current value to the default and clear
// the boolean that says that the value has been set.
enum_value->Clear();
@@ -94,10 +93,13 @@ Property::Property (const PropertyDefinition &definition) :
break;
case OptionValue::eTypeFileSpec:
+ {
// "definition.default_uint_value" represents if the "definition.default_cstr_value" should
// be resolved or not
- m_value_sp.reset (new OptionValueFileSpec(FileSpec(definition.default_cstr_value, definition.default_uint_value != 0)));
+ const bool resolve = definition.default_uint_value != 0;
+ m_value_sp.reset (new OptionValueFileSpec(FileSpec(definition.default_cstr_value, resolve), resolve));
break;
+ }
case OptionValue::eTypeFileSpecList:
// "definition.default_uint_value" is not used for a OptionValue::eTypeFileSpecList
@@ -119,6 +121,21 @@ Property::Property (const PropertyDefinition &definition) :
}
break;
+ case OptionValue::eTypeLanguage:
+ // "definition.default_uint_value" is the default language enumeration value if
+ // "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the default
+ // value.
+ {
+ LanguageType new_lang = eLanguageTypeUnknown;
+ if (definition.default_cstr_value)
+ LanguageRuntime::GetLanguageTypeFromString(definition.default_cstr_value);
+ else
+ new_lang = (LanguageType)definition.default_uint_value;
+ m_value_sp.reset (new OptionValueLanguage(new_lang));
+ }
+ break;
+
case OptionValue::eTypeFormatEntity:
// "definition.default_cstr_value" as a string value that represents the default
m_value_sp.reset (new OptionValueFormatEntity(definition.default_cstr_value));
diff --git a/source/Interpreter/PythonDataObjects.cpp b/source/Interpreter/PythonDataObjects.cpp
index 3ea6c0dbe3e5..a581a0b3601a 100644
--- a/source/Interpreter/PythonDataObjects.cpp
+++ b/source/Interpreter/PythonDataObjects.cpp
@@ -23,19 +23,20 @@
#include "lldb/Host/File.h"
#include "lldb/Interpreter/PythonDataObjects.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
using namespace lldb_private;
using namespace lldb;
+void
+StructuredPythonObject::Dump(Stream &s) const
+{
+ s << "Python Obj: 0x" << GetValue();
+}
+
//----------------------------------------------------------------------
// PythonObject
//----------------------------------------------------------------------
-PythonObject::PythonObject (const lldb::ScriptInterpreterObjectSP &script_object_sp) :
- m_py_obj (nullptr)
-{
- if (script_object_sp)
- Reset ((PyObject *)script_object_sp->GetObject());
-}
void
PythonObject::Dump (Stream &strm) const
@@ -62,6 +63,23 @@ PythonObject::Dump (Stream &strm) const
strm.PutCString ("NULL");
}
+PyObjectType
+PythonObject::GetObjectType() const
+{
+ if (IsNULLOrNone())
+ return PyObjectType::None;
+
+ if (PyList_Check(m_py_obj))
+ return PyObjectType::List;
+ if (PyDict_Check(m_py_obj))
+ return PyObjectType::Dictionary;
+ if (PyString_Check(m_py_obj))
+ return PyObjectType::String;
+ if (PyInt_Check(m_py_obj) || PyLong_Check(m_py_obj))
+ return PyObjectType::Integer;
+ return PyObjectType::Unknown;
+}
+
PythonString
PythonObject::Repr ()
{
@@ -90,6 +108,26 @@ PythonObject::IsNULLOrNone () const
return ((m_py_obj == nullptr) || (m_py_obj == Py_None));
}
+StructuredData::ObjectSP
+PythonObject::CreateStructuredObject() const
+{
+ switch (GetObjectType())
+ {
+ case PyObjectType::Dictionary:
+ return PythonDictionary(m_py_obj).CreateStructuredDictionary();
+ case PyObjectType::Integer:
+ return PythonInteger(m_py_obj).CreateStructuredInteger();
+ case PyObjectType::List:
+ return PythonList(m_py_obj).CreateStructuredArray();
+ case PyObjectType::String:
+ return PythonString(m_py_obj).CreateStructuredString();
+ case PyObjectType::None:
+ return StructuredData::ObjectSP();
+ default:
+ return StructuredData::ObjectSP(new StructuredPythonObject(m_py_obj));
+ }
+}
+
//----------------------------------------------------------------------
// PythonString
//----------------------------------------------------------------------
@@ -106,14 +144,12 @@ PythonString::PythonString (const PythonObject &object) :
Reset(object.get()); // Use "Reset()" to ensure that py_obj is a string
}
-PythonString::PythonString (const lldb::ScriptInterpreterObjectSP &script_object_sp) :
- PythonObject()
+PythonString::PythonString (llvm::StringRef string) :
+ PythonObject(PyString_FromStringAndSize(string.data(), string.size()))
{
- if (script_object_sp)
- Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a string
}
-PythonString::PythonString (const char* string) :
+PythonString::PythonString(const char *string) :
PythonObject(PyString_FromString(string))
{
}
@@ -137,12 +173,12 @@ PythonString::Reset (PyObject *py_obj)
return py_obj == nullptr;
}
-const char*
+llvm::StringRef
PythonString::GetString() const
{
if (m_py_obj)
- return PyString_AsString(m_py_obj);
- return nullptr;
+ return llvm::StringRef(PyString_AsString(m_py_obj), GetSize());
+ return llvm::StringRef();
}
size_t
@@ -154,9 +190,17 @@ PythonString::GetSize() const
}
void
-PythonString::SetString (const char* string)
+PythonString::SetString (llvm::StringRef string)
{
- PythonObject::Reset(PyString_FromString(string));
+ PythonObject::Reset(PyString_FromStringAndSize(string.data(), string.size()));
+}
+
+StructuredData::StringSP
+PythonString::CreateStructuredString() const
+{
+ StructuredData::StringSP result(new StructuredData::String);
+ result->SetValue(GetString());
+ return result;
}
//----------------------------------------------------------------------
@@ -175,13 +219,6 @@ PythonInteger::PythonInteger (const PythonObject &object) :
Reset(object.get()); // Use "Reset()" to ensure that py_obj is a integer type
}
-PythonInteger::PythonInteger (const lldb::ScriptInterpreterObjectSP &script_object_sp) :
- PythonObject()
-{
- if (script_object_sp)
- Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a string
-}
-
PythonInteger::PythonInteger (int64_t value) :
PythonObject()
{
@@ -207,7 +244,7 @@ PythonInteger::Reset (PyObject *py_obj)
}
int64_t
-PythonInteger::GetInteger()
+PythonInteger::GetInteger() const
{
if (m_py_obj)
{
@@ -225,6 +262,14 @@ PythonInteger::SetInteger (int64_t value)
PythonObject::Reset(PyLong_FromLongLong(value));
}
+StructuredData::IntegerSP
+PythonInteger::CreateStructuredInteger() const
+{
+ StructuredData::IntegerSP result(new StructuredData::Integer);
+ result->SetValue(GetInteger());
+ return result;
+}
+
//----------------------------------------------------------------------
// PythonList
//----------------------------------------------------------------------
@@ -252,13 +297,6 @@ PythonList::PythonList (const PythonObject &object) :
Reset(object.get()); // Use "Reset()" to ensure that py_obj is a list
}
-PythonList::PythonList (const lldb::ScriptInterpreterObjectSP &script_object_sp) :
- PythonObject()
-{
- if (script_object_sp)
- Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a list
-}
-
PythonList::~PythonList ()
{
}
@@ -274,7 +312,7 @@ PythonList::Reset (PyObject *py_obj)
}
uint32_t
-PythonList::GetSize()
+PythonList::GetSize() const
{
if (m_py_obj)
return PyList_GET_SIZE(m_py_obj);
@@ -282,7 +320,7 @@ PythonList::GetSize()
}
PythonObject
-PythonList::GetItemAtIndex (uint32_t index)
+PythonList::GetItemAtIndex(uint32_t index) const
{
if (m_py_obj)
return PythonObject(PyList_GetItem(m_py_obj, index));
@@ -303,6 +341,19 @@ PythonList::AppendItem (const PythonObject &object)
PyList_Append(m_py_obj, object.get());
}
+StructuredData::ArraySP
+PythonList::CreateStructuredArray() const
+{
+ StructuredData::ArraySP result(new StructuredData::Array);
+ uint32_t count = GetSize();
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ PythonObject obj = GetItemAtIndex(i);
+ result->AddItem(obj.CreateStructuredObject());
+ }
+ return result;
+}
+
//----------------------------------------------------------------------
// PythonDictionary
//----------------------------------------------------------------------
@@ -325,13 +376,6 @@ PythonDictionary::PythonDictionary (const PythonObject &object) :
Reset(object.get()); // Use "Reset()" to ensure that py_obj is a dictionary
}
-PythonDictionary::PythonDictionary (const lldb::ScriptInterpreterObjectSP &script_object_sp) :
- PythonObject ()
-{
- if (script_object_sp)
- Reset((PyObject *)script_object_sp->GetObject()); // Use "Reset()" to ensure that py_obj is a dictionary
-}
-
PythonDictionary::~PythonDictionary ()
{
}
@@ -347,7 +391,7 @@ PythonDictionary::Reset (PyObject *py_obj)
}
uint32_t
-PythonDictionary::GetSize()
+PythonDictionary::GetSize() const
{
if (m_py_obj)
return PyDict_Size(m_py_obj);
@@ -460,4 +504,21 @@ PythonDictionary::SetItemForKey (const PythonString &key, const PythonObject &va
PyDict_SetItem(m_py_obj, key.get(), value.get());
}
+StructuredData::DictionarySP
+PythonDictionary::CreateStructuredDictionary() const
+{
+ StructuredData::DictionarySP result(new StructuredData::Dictionary);
+ PythonList keys(GetKeys());
+ uint32_t num_keys = keys.GetSize();
+ for (uint32_t i = 0; i < num_keys; ++i)
+ {
+ PythonObject key = keys.GetItemAtIndex(i);
+ PythonString key_str = key.Str();
+ PythonObject value = GetItemForKey(key);
+ StructuredData::ObjectSP structured_value = value.CreateStructuredObject();
+ result->AddItem(key_str.GetString(), structured_value);
+ }
+ return result;
+}
+
#endif
diff --git a/source/Interpreter/ScriptInterpreter.cpp b/source/Interpreter/ScriptInterpreter.cpp
index 45e3b44cc0ac..f1ec50e663fd 100644
--- a/source/Interpreter/ScriptInterpreter.cpp
+++ b/source/Interpreter/ScriptInterpreter.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/ScriptInterpreter.h"
#include <string>
@@ -19,7 +17,6 @@
#include "lldb/Core/Stream.h"
#include "lldb/Core/StringList.h"
#include "lldb/Interpreter/CommandReturnObject.h"
-#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Utility/PseudoTerminal.h"
using namespace lldb;
@@ -110,57 +107,3 @@ ScriptInterpreter::AcquireInterpreterLock ()
{
return std::unique_ptr<ScriptInterpreterLocker>(new ScriptInterpreterLocker());
}
-
-void
-ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
- SWIGBreakpointCallbackFunction swig_breakpoint_callback,
- SWIGWatchpointCallbackFunction swig_watchpoint_callback,
- SWIGPythonTypeScriptCallbackFunction swig_typescript_callback,
- SWIGPythonCreateSyntheticProvider swig_synthetic_script,
- SWIGPythonCalculateNumChildren swig_calc_children,
- SWIGPythonGetChildAtIndex swig_get_child_index,
- SWIGPythonGetIndexOfChildWithName swig_get_index_child,
- SWIGPythonCastPyObjectToSBValue swig_cast_to_sbvalue ,
- SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue,
- SWIGPythonUpdateSynthProviderInstance swig_update_provider,
- SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider,
- SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider,
- SWIGPythonCallCommand swig_call_command,
- SWIGPythonCallModuleInit swig_call_module_init,
- SWIGPythonCreateOSPlugin swig_create_os_plugin,
- SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
- SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
- SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
- SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame,
- SWIGPythonScriptKeyword_Value swig_run_script_keyword_value,
- SWIGPython_GetDynamicSetting swig_plugin_get,
- SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script,
- SWIGPythonCallThreadPlan swig_call_thread_plan)
-{
-#ifndef LLDB_DISABLE_PYTHON
- ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback,
- swig_breakpoint_callback,
- swig_watchpoint_callback,
- swig_typescript_callback,
- swig_synthetic_script,
- swig_calc_children,
- swig_get_child_index,
- swig_get_index_child,
- swig_cast_to_sbvalue ,
- swig_get_valobj_sp_from_sbvalue,
- swig_update_provider,
- swig_mighthavechildren_provider,
- swig_getvalue_provider,
- swig_call_command,
- swig_call_module_init,
- swig_create_os_plugin,
- swig_run_script_keyword_process,
- swig_run_script_keyword_thread,
- swig_run_script_keyword_target,
- swig_run_script_keyword_frame,
- swig_run_script_keyword_value,
- swig_plugin_get,
- swig_thread_plan_script,
- swig_call_thread_plan);
-#endif // #ifndef LLDB_DISABLE_PYTHON
-}
diff --git a/source/Interpreter/ScriptInterpreterNone.cpp b/source/Interpreter/ScriptInterpreterNone.cpp
index e33480d1a6d5..909a1161c9c1 100644
--- a/source/Interpreter/ScriptInterpreterNone.cpp
+++ b/source/Interpreter/ScriptInterpreterNone.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Interpreter/ScriptInterpreterNone.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
diff --git a/source/Interpreter/ScriptInterpreterPython.cpp b/source/Interpreter/ScriptInterpreterPython.cpp
index 8155cbb189fe..8f60793550c3 100644
--- a/source/Interpreter/ScriptInterpreterPython.cpp
+++ b/source/Interpreter/ScriptInterpreterPython.cpp
@@ -30,6 +30,8 @@
#include "lldb/Core/Communication.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Timer.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Pipe.h"
@@ -43,34 +45,39 @@
#include "lldb/Host/windows/ConnectionGenericFileWindows.h"
#endif
+#include "llvm/ADT/StringRef.h"
+
using namespace lldb;
using namespace lldb_private;
-
-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::SWIGPythonGetValueSynthProviderInstance g_swig_getvalue_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::SWIGPythonScriptKeyword_Value g_swig_run_script_keyword_value = nullptr;
-static ScriptInterpreter::SWIGPython_GetDynamicSetting g_swig_plugin_get = nullptr;
-static ScriptInterpreter::SWIGPythonCreateScriptedThreadPlan g_swig_thread_plan_script = nullptr;
-static ScriptInterpreter::SWIGPythonCallThreadPlan g_swig_call_thread_plan = nullptr;
+static ScriptInterpreterPython::SWIGInitCallback g_swig_init_callback = nullptr;
+static ScriptInterpreterPython::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = nullptr;
+static ScriptInterpreterPython::SWIGWatchpointCallbackFunction g_swig_watchpoint_callback = nullptr;
+static ScriptInterpreterPython::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = nullptr;
+static ScriptInterpreterPython::SWIGPythonCreateSyntheticProvider g_swig_synthetic_script = nullptr;
+static ScriptInterpreterPython::SWIGPythonCreateCommandObject g_swig_create_cmd = nullptr;
+static ScriptInterpreterPython::SWIGPythonCalculateNumChildren g_swig_calc_children = nullptr;
+static ScriptInterpreterPython::SWIGPythonGetChildAtIndex g_swig_get_child_index = nullptr;
+static ScriptInterpreterPython::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = nullptr;
+static ScriptInterpreterPython::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = nullptr;
+static ScriptInterpreterPython::SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = nullptr;
+static ScriptInterpreterPython::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = nullptr;
+static ScriptInterpreterPython::SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = nullptr;
+static ScriptInterpreterPython::SWIGPythonGetValueSynthProviderInstance g_swig_getvalue_provider = nullptr;
+static ScriptInterpreterPython::SWIGPythonCallCommand g_swig_call_command = nullptr;
+static ScriptInterpreterPython::SWIGPythonCallCommandObject g_swig_call_command_object = nullptr;
+static ScriptInterpreterPython::SWIGPythonCallModuleInit g_swig_call_module_init = nullptr;
+static ScriptInterpreterPython::SWIGPythonCreateOSPlugin g_swig_create_os_plugin = nullptr;
+static ScriptInterpreterPython::SWIGPythonScriptKeyword_Process g_swig_run_script_keyword_process = nullptr;
+static ScriptInterpreterPython::SWIGPythonScriptKeyword_Thread g_swig_run_script_keyword_thread = nullptr;
+static ScriptInterpreterPython::SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = nullptr;
+static ScriptInterpreterPython::SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = nullptr;
+static ScriptInterpreterPython::SWIGPythonScriptKeyword_Value g_swig_run_script_keyword_value = nullptr;
+static ScriptInterpreterPython::SWIGPython_GetDynamicSetting g_swig_plugin_get = nullptr;
+static ScriptInterpreterPython::SWIGPythonCreateScriptedThreadPlan g_swig_thread_plan_script = nullptr;
+static ScriptInterpreterPython::SWIGPythonCallThreadPlan g_swig_call_thread_plan = nullptr;
+
+static bool g_initialized = false;
static std::string
ReadPythonBacktrace (PyObject* py_backtrace);
@@ -171,8 +178,7 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete
m_lock_count (0),
m_command_thread_state (nullptr)
{
-
- ScriptInterpreterPython::InitializePrivate ();
+ assert(g_initialized && "ScriptInterpreterPython created but initialize has not been called!");
m_dictionary_name.append("_dict");
StreamString run_string;
@@ -185,17 +191,7 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete
run_string.Clear();
- // Importing 'lldb' module calls SBDebugger::Initialize, which calls Debugger::Initialize, which increments a
- // global debugger ref-count; therefore we need to check the ref-count before and after importing lldb, and if the
- // ref-count increased we need to call Debugger::Terminate here to decrement the ref-count so that when the final
- // call to Debugger::Terminate is made, the ref-count has the correct value.
- //
- // Bonus question: Why doesn't the ref-count always increase? Because sometimes lldb has already been imported, in
- // which case the code inside it, including the call to SBDebugger::Initialize(), does not get executed.
-
- int old_count = Debugger::TestDebuggerRefCount();
-
- run_string.Printf ("run_one_line (%s, 'import copy, os, re, sys, uuid, lldb')", m_dictionary_name.c_str());
+ run_string.Printf ("run_one_line (%s, 'import copy, keyword, os, re, sys, uuid, lldb')", m_dictionary_name.c_str());
PyRun_SimpleString (run_string.GetData());
// WARNING: temporary code that loads Cocoa formatters - this should be done on a per-platform basis rather than loading the whole set
@@ -205,11 +201,6 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete
PyRun_SimpleString (run_string.GetData());
run_string.Clear();
- int new_count = Debugger::TestDebuggerRefCount();
-
- if (new_count > old_count)
- Debugger::Terminate();
-
run_string.Printf ("run_one_line (%s, 'import lldb.embedded_interpreter; from lldb.embedded_interpreter import run_python_interpreter; from lldb.embedded_interpreter import run_one_line')", m_dictionary_name.c_str());
PyRun_SimpleString (run_string.GetData());
run_string.Clear();
@@ -393,6 +384,13 @@ ScriptInterpreterPython::LeaveSession ()
m_session_is_active = false;
}
+static PyObject *
+PyFile_FromFile_Const(FILE *fp, const char *name, const char *mode, int (*close)(FILE *))
+{
+ // Read through the Python source, doesn't seem to modify these strings
+ return PyFile_FromFile(fp, const_cast<char*>(name), const_cast<char*>(mode), close);
+}
+
bool
ScriptInterpreterPython::EnterSession (uint16_t on_entry_flags,
FILE *in,
@@ -458,7 +456,7 @@ ScriptInterpreterPython::EnterSession (uint16_t on_entry_flags,
{
m_saved_stdin.Reset(sys_module_dict.GetItemForKey("stdin"));
// This call can deadlock your process if the file is locked
- PyObject *new_file = PyFile_FromFile (in, (char *) "", (char *) "r", nullptr);
+ PyObject *new_file = PyFile_FromFile_Const (in, "", "r", nullptr);
sys_module_dict.SetItemForKey ("stdin", new_file);
Py_DECREF (new_file);
}
@@ -470,7 +468,7 @@ ScriptInterpreterPython::EnterSession (uint16_t on_entry_flags,
{
m_saved_stdout.Reset(sys_module_dict.GetItemForKey("stdout"));
- PyObject *new_file = PyFile_FromFile (out, (char *) "", (char *) "w", nullptr);
+ PyObject *new_file = PyFile_FromFile_Const (out, "", "w", nullptr);
sys_module_dict.SetItemForKey ("stdout", new_file);
Py_DECREF (new_file);
}
@@ -483,7 +481,7 @@ ScriptInterpreterPython::EnterSession (uint16_t on_entry_flags,
{
m_saved_stderr.Reset(sys_module_dict.GetItemForKey("stderr"));
- PyObject *new_file = PyFile_FromFile (err, (char *) "", (char *) "w", nullptr);
+ PyObject *new_file = PyFile_FromFile_Const (err, "", "w", nullptr);
sys_module_dict.SetItemForKey ("stderr", new_file);
Py_DECREF (new_file);
}
@@ -738,22 +736,21 @@ public:
}
- virtual
- ~IOHandlerPythonInterpreter()
+ ~IOHandlerPythonInterpreter() override
{
}
- virtual ConstString
- GetControlSequence (char ch)
+ ConstString
+ GetControlSequence (char ch) override
{
if (ch == 'd')
return ConstString("quit()\n");
return ConstString();
}
- virtual void
- Run ()
+ void
+ Run () override
{
if (m_python)
{
@@ -799,32 +796,20 @@ public:
SetIsDone(true);
}
- virtual void
- Hide ()
- {
-
- }
-
- virtual void
- Refresh ()
- {
-
- }
-
- virtual void
- Cancel ()
+ void
+ Cancel () override
{
}
- virtual bool
- Interrupt ()
+ bool
+ Interrupt () override
{
return m_python->Interrupt();
}
- virtual void
- GotEOF()
+ void
+ GotEOF() override
{
}
@@ -1348,15 +1333,15 @@ ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, std::st
return true;
}
-lldb::ScriptInterpreterObjectSP
-ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, lldb::ProcessSP process_sp)
+StructuredData::GenericSP
+ScriptInterpreterPython::OSPlugin_CreatePluginObject(const char *class_name, lldb::ProcessSP process_sp)
{
if (class_name == nullptr || class_name[0] == '\0')
- return lldb::ScriptInterpreterObjectSP();
-
+ return StructuredData::GenericSP();
+
if (!process_sp)
- return lldb::ScriptInterpreterObjectSP();
-
+ return StructuredData::GenericSP();
+
void* ret_val;
{
@@ -1367,12 +1352,12 @@ ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, ll
m_dictionary_name.c_str(),
process_sp);
}
-
- return MakeScriptObject(ret_val);
+
+ return StructuredData::GenericSP(new StructuredPythonObject(ret_val));
}
-lldb::ScriptInterpreterObjectSP
-ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp)
+StructuredData::DictionarySP
+ScriptInterpreterPython::OSPlugin_RegisterInfo(StructuredData::ObjectSP os_plugin_object_sp)
{
Locker py_lock(this,
Locker::AcquireLock | Locker::NoSTDIN,
@@ -1381,13 +1366,17 @@ ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP
static char callee_name[] = "get_register_info";
if (!os_plugin_object_sp)
- return lldb::ScriptInterpreterObjectSP();
-
- PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
-
+ return StructuredData::DictionarySP();
+
+ StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
+ if (!generic)
+ return nullptr;
+
+ PyObject *implementor = (PyObject *)generic->GetValue();
+
if (implementor == nullptr || implementor == Py_None)
- return lldb::ScriptInterpreterObjectSP();
-
+ return StructuredData::DictionarySP();
+
PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
if (PyErr_Occurred())
@@ -1398,7 +1387,7 @@ ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP
if (pmeth == nullptr || pmeth == Py_None)
{
Py_XDECREF(pmeth);
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::DictionarySP();
}
if (PyCallable_Check(pmeth) == 0)
@@ -1409,7 +1398,7 @@ ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP
}
Py_XDECREF(pmeth);
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::DictionarySP();
}
if (PyErr_Occurred())
@@ -1428,27 +1417,31 @@ ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP
PyErr_Print();
PyErr_Clear();
}
-
- return MakeScriptObject(py_return);
+
+ PythonDictionary result_dict(py_return);
+ return result_dict.CreateStructuredDictionary();
}
-lldb::ScriptInterpreterObjectSP
-ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp)
+StructuredData::ArraySP
+ScriptInterpreterPython::OSPlugin_ThreadsInfo(StructuredData::ObjectSP os_plugin_object_sp)
{
Locker py_lock (this,
Locker::AcquireLock | Locker::NoSTDIN,
Locker::FreeLock);
static char callee_name[] = "get_thread_info";
-
+
if (!os_plugin_object_sp)
- return lldb::ScriptInterpreterObjectSP();
-
- PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
-
+ return StructuredData::ArraySP();
+
+ StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
+ if (!generic)
+ return nullptr;
+ PyObject *implementor = (PyObject *)generic->GetValue();
+
if (implementor == nullptr || implementor == Py_None)
- return lldb::ScriptInterpreterObjectSP();
-
+ return StructuredData::ArraySP();
+
PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
if (PyErr_Occurred())
@@ -1459,7 +1452,7 @@ ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP o
if (pmeth == nullptr || pmeth == Py_None)
{
Py_XDECREF(pmeth);
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::ArraySP();
}
if (PyCallable_Check(pmeth) == 0)
@@ -1470,7 +1463,7 @@ ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP o
}
Py_XDECREF(pmeth);
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::ArraySP();
}
if (PyErr_Occurred())
@@ -1489,8 +1482,9 @@ ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP o
PyErr_Print();
PyErr_Clear();
}
-
- return MakeScriptObject(py_return);
+
+ PythonList ResultList(py_return);
+ return ResultList.CreateStructuredArray();
}
// GetPythonValueFormatString provides a system independent type safe way to
@@ -1519,9 +1513,8 @@ template <> const char *GetPythonValueFormatString (unsigned long long) { return
template <> const char *GetPythonValueFormatString (float t) { return "f"; }
template <> const char *GetPythonValueFormatString (double t) { return "d"; }
-lldb::ScriptInterpreterObjectSP
-ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
- lldb::tid_t tid)
+StructuredData::StringSP
+ScriptInterpreterPython::OSPlugin_RegisterContextData(StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t tid)
{
Locker py_lock (this,
Locker::AcquireLock | Locker::NoSTDIN,
@@ -1531,12 +1524,15 @@ ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterOb
static char *param_format = const_cast<char *>(GetPythonValueFormatString(tid));
if (!os_plugin_object_sp)
- return lldb::ScriptInterpreterObjectSP();
-
- PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
-
+ return StructuredData::StringSP();
+
+ StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
+ if (!generic)
+ return nullptr;
+ PyObject *implementor = (PyObject *)generic->GetValue();
+
if (implementor == nullptr || implementor == Py_None)
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::StringSP();
PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
@@ -1548,7 +1544,7 @@ ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterOb
if (pmeth == nullptr || pmeth == Py_None)
{
Py_XDECREF(pmeth);
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::StringSP();
}
if (PyCallable_Check(pmeth) == 0)
@@ -1559,7 +1555,7 @@ ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterOb
}
Py_XDECREF(pmeth);
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::StringSP();
}
if (PyErr_Occurred())
@@ -1578,14 +1574,12 @@ ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterOb
PyErr_Print();
PyErr_Clear();
}
-
- return MakeScriptObject(py_return);
+ PythonString result_string(py_return);
+ return result_string.CreateStructuredString();
}
-lldb::ScriptInterpreterObjectSP
-ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
- lldb::tid_t tid,
- lldb::addr_t context)
+StructuredData::DictionarySP
+ScriptInterpreterPython::OSPlugin_CreateThread(StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t tid, lldb::addr_t context)
{
Locker py_lock(this,
Locker::AcquireLock | Locker::NoSTDIN,
@@ -1597,13 +1591,16 @@ ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP
param_format += GetPythonValueFormatString(context);
if (!os_plugin_object_sp)
- return lldb::ScriptInterpreterObjectSP();
-
- PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
-
+ return StructuredData::DictionarySP();
+
+ StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
+ if (!generic)
+ return nullptr;
+ PyObject *implementor = (PyObject *)generic->GetValue();
+
if (implementor == nullptr || implementor == Py_None)
- return lldb::ScriptInterpreterObjectSP();
-
+ return StructuredData::DictionarySP();
+
PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
if (PyErr_Occurred())
@@ -1614,7 +1611,7 @@ ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP
if (pmeth == nullptr || pmeth == Py_None)
{
Py_XDECREF(pmeth);
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::DictionarySP();
}
if (PyCallable_Check(pmeth) == 0)
@@ -1625,7 +1622,7 @@ ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP
}
Py_XDECREF(pmeth);
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::DictionarySP();
}
if (PyErr_Occurred())
@@ -1644,27 +1641,27 @@ ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP
PyErr_Print();
PyErr_Clear();
}
-
- return MakeScriptObject(py_return);
+
+ PythonDictionary result_dict(py_return);
+ return result_dict.CreateStructuredDictionary();
}
-lldb::ScriptInterpreterObjectSP
-ScriptInterpreterPython::CreateScriptedThreadPlan (const char *class_name,
- lldb::ThreadPlanSP thread_plan_sp)
+StructuredData::ObjectSP
+ScriptInterpreterPython::CreateScriptedThreadPlan(const char *class_name, lldb::ThreadPlanSP thread_plan_sp)
{
if (class_name == nullptr || class_name[0] == '\0')
- return lldb::ScriptInterpreterObjectSP();
-
+ return StructuredData::ObjectSP();
+
if (!thread_plan_sp.get())
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::ObjectSP();
Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger();
ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
ScriptInterpreterPython *python_interpreter = static_cast<ScriptInterpreterPython *>(script_interpreter);
if (!script_interpreter)
- return lldb::ScriptInterpreterObjectSP();
-
+ return StructuredData::ObjectSP();
+
void* ret_val;
{
@@ -1674,20 +1671,21 @@ ScriptInterpreterPython::CreateScriptedThreadPlan (const char *class_name,
python_interpreter->m_dictionary_name.c_str(),
thread_plan_sp);
}
-
- return MakeScriptObject(ret_val);
+
+ return StructuredData::ObjectSP(new StructuredPythonObject(ret_val));
}
bool
-ScriptInterpreterPython::ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp,
- Event *event,
- bool &script_error)
+ScriptInterpreterPython::ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error)
{
bool explains_stop = true;
+ StructuredData::Generic *generic = nullptr;
if (implementor_sp)
+ generic = implementor_sp->GetAsGeneric();
+ if (generic)
{
Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
- explains_stop = g_swig_call_thread_plan (implementor_sp->GetObject(), "explains_stop", event, script_error);
+ explains_stop = g_swig_call_thread_plan(generic->GetValue(), "explains_stop", event, script_error);
if (script_error)
return true;
}
@@ -1695,15 +1693,16 @@ ScriptInterpreterPython::ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreter
}
bool
-ScriptInterpreterPython::ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp,
- Event *event,
- bool &script_error)
+ScriptInterpreterPython::ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error)
{
bool should_stop = true;
+ StructuredData::Generic *generic = nullptr;
if (implementor_sp)
+ generic = implementor_sp->GetAsGeneric();
+ if (generic)
{
Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
- should_stop = g_swig_call_thread_plan (implementor_sp->GetObject(), "should_stop", event, script_error);
+ should_stop = g_swig_call_thread_plan(generic->GetValue(), "should_stop", event, script_error);
if (script_error)
return true;
}
@@ -1711,14 +1710,16 @@ ScriptInterpreterPython::ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterOb
}
lldb::StateType
-ScriptInterpreterPython::ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp,
- bool &script_error)
+ScriptInterpreterPython::ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp, bool &script_error)
{
bool should_step = false;
+ StructuredData::Generic *generic = nullptr;
if (implementor_sp)
+ generic = implementor_sp->GetAsGeneric();
+ if (generic)
{
Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
- should_step = g_swig_call_thread_plan (implementor_sp->GetObject(), "should_step", NULL, script_error);
+ should_step = g_swig_call_thread_plan(generic->GetValue(), "should_step", NULL, script_error);
if (script_error)
should_step = true;
}
@@ -1728,72 +1729,69 @@ ScriptInterpreterPython::ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterO
return lldb::eStateRunning;
}
-
-lldb::ScriptInterpreterObjectSP
-ScriptInterpreterPython::LoadPluginModule (const FileSpec& file_spec,
- lldb_private::Error& error)
+StructuredData::ObjectSP
+ScriptInterpreterPython::LoadPluginModule(const FileSpec &file_spec, lldb_private::Error &error)
{
if (!file_spec.Exists())
{
error.SetErrorString("no such file");
- return lldb::ScriptInterpreterObjectSP();
+ return StructuredData::ObjectSP();
}
- ScriptInterpreterObjectSP module_sp;
-
+ StructuredData::ObjectSP module_sp;
+
if (LoadScriptingModule(file_spec.GetPath().c_str(),true,true,error,&module_sp))
return module_sp;
-
- return lldb::ScriptInterpreterObjectSP();
+
+ return StructuredData::ObjectSP();
}
-lldb::ScriptInterpreterObjectSP
-ScriptInterpreterPython::GetDynamicSettings (lldb::ScriptInterpreterObjectSP plugin_module_sp,
- Target* target,
- const char* setting_name,
- lldb_private::Error& error)
+StructuredData::DictionarySP
+ScriptInterpreterPython::GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target, const char *setting_name,
+ lldb_private::Error &error)
{
- if (!plugin_module_sp || !target || !setting_name || !setting_name[0])
- return lldb::ScriptInterpreterObjectSP();
-
- if (!g_swig_plugin_get)
- return lldb::ScriptInterpreterObjectSP();
-
+ if (!plugin_module_sp || !target || !setting_name || !setting_name[0] || !g_swig_plugin_get)
+ return StructuredData::DictionarySP();
+ StructuredData::Generic *generic = plugin_module_sp->GetAsGeneric();
+ if (!generic)
+ return StructuredData::DictionarySP();
+
PyObject *reply_pyobj = nullptr;
{
Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
TargetSP target_sp(target->shared_from_this());
- reply_pyobj = (PyObject*)g_swig_plugin_get(plugin_module_sp->GetObject(),setting_name,target_sp);
+ reply_pyobj = (PyObject *)g_swig_plugin_get(generic->GetValue(), setting_name, target_sp);
}
-
- return MakeScriptObject(reply_pyobj);
+
+ PythonDictionary py_dict(reply_pyobj);
+
+ return py_dict.CreateStructuredDictionary();
}
-lldb::ScriptInterpreterObjectSP
-ScriptInterpreterPython::CreateSyntheticScriptedProvider (const char *class_name,
- lldb::ValueObjectSP valobj)
+StructuredData::ObjectSP
+ScriptInterpreterPython::CreateSyntheticScriptedProvider(const char *class_name, lldb::ValueObjectSP valobj)
{
if (class_name == nullptr || class_name[0] == '\0')
- return lldb::ScriptInterpreterObjectSP();
-
+ return StructuredData::ObjectSP();
+
if (!valobj.get())
- return lldb::ScriptInterpreterObjectSP();
-
+ return StructuredData::ObjectSP();
+
ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
Target *target = exe_ctx.GetTargetPtr();
if (!target)
- return lldb::ScriptInterpreterObjectSP();
-
+ return StructuredData::ObjectSP();
+
Debugger &debugger = target->GetDebugger();
ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
if (!script_interpreter)
- return lldb::ScriptInterpreterObjectSP();
-
- void* ret_val;
+ return StructuredData::ObjectSP();
+
+ void *ret_val = nullptr;
{
Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
@@ -1801,8 +1799,31 @@ ScriptInterpreterPython::CreateSyntheticScriptedProvider (const char *class_name
python_interpreter->m_dictionary_name.c_str(),
valobj);
}
+
+ return StructuredData::ObjectSP(new StructuredPythonObject(ret_val));
+}
+
+StructuredData::GenericSP
+ScriptInterpreterPython::CreateScriptCommandObject (const char *class_name)
+{
+ DebuggerSP debugger_sp(GetCommandInterpreter().GetDebugger().shared_from_this());
+
+ if (class_name == nullptr || class_name[0] == '\0')
+ return StructuredData::GenericSP();
+
+ if (!debugger_sp.get())
+ return StructuredData::GenericSP();
+
+ void* ret_val;
+
+ {
+ Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+ ret_val = g_swig_create_cmd (class_name,
+ m_dictionary_name.c_str(),
+ debugger_sp);
+ }
- return MakeScriptObject(ret_val);
+ return StructuredData::GenericSP(new StructuredPythonObject(ret_val));
}
bool
@@ -1869,11 +1890,9 @@ ScriptInterpreterPython::GenerateWatchpointCommandCallbackData (StringList &user
}
bool
-ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name,
- lldb::ValueObjectSP valobj,
- lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
- const TypeSummaryOptions& options,
- std::string& retval)
+ScriptInterpreterPython::GetScriptedSummary(const char *python_function_name, lldb::ValueObjectSP valobj,
+ StructuredData::ObjectSP &callee_wrapper_sp, const TypeSummaryOptions &options,
+ std::string &retval)
{
Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
@@ -1883,13 +1902,19 @@ ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name,
retval.assign("<no object>");
return false;
}
-
- void* old_callee = (callee_wrapper_sp ? callee_wrapper_sp->GetObject() : nullptr);
+
+ void *old_callee = nullptr;
+ StructuredData::Generic *generic = nullptr;
+ if (callee_wrapper_sp)
+ {
+ generic = callee_wrapper_sp->GetAsGeneric();
+ if (generic)
+ old_callee = generic->GetValue();
+ }
void* new_callee = old_callee;
bool ret_val;
- if (python_function_name
- && *python_function_name)
+ if (python_function_name && *python_function_name)
{
{
Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
@@ -1913,10 +1938,9 @@ ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name,
}
if (new_callee && old_callee != new_callee)
- callee_wrapper_sp = MakeScriptObject(new_callee);
-
+ callee_wrapper_sp.reset(new StructuredPythonObject(new_callee));
+
return ret_val;
-
}
void
@@ -2042,20 +2066,21 @@ ScriptInterpreterPython::WatchpointCallbackFunction
}
size_t
-ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor_sp)
+ScriptInterpreterPython::CalculateNumChildren(const StructuredData::ObjectSP &implementor_sp)
{
if (!implementor_sp)
return 0;
-
- void* implementor = implementor_sp->GetObject();
-
+ StructuredData::Generic *generic = implementor_sp->GetAsGeneric();
+ if (!generic)
+ return 0;
+ void *implementor = generic->GetValue();
if (!implementor)
return 0;
if (!g_swig_calc_children)
return 0;
- uint32_t ret_val = 0;
+ size_t ret_val = 0;
{
Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
@@ -2066,13 +2091,15 @@ ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObje
}
lldb::ValueObjectSP
-ScriptInterpreterPython::GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor_sp, uint32_t idx)
+ScriptInterpreterPython::GetChildAtIndex(const StructuredData::ObjectSP &implementor_sp, uint32_t idx)
{
if (!implementor_sp)
return lldb::ValueObjectSP();
-
- void* implementor = implementor_sp->GetObject();
-
+
+ StructuredData::Generic *generic = implementor_sp->GetAsGeneric();
+ if (!generic)
+ return lldb::ValueObjectSP();
+ void *implementor = generic->GetValue();
if (!implementor)
return lldb::ValueObjectSP();
@@ -2102,13 +2129,15 @@ ScriptInterpreterPython::GetChildAtIndex (const lldb::ScriptInterpreterObjectSP&
}
int
-ScriptInterpreterPython::GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor_sp, const char* child_name)
+ScriptInterpreterPython::GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor_sp, const char *child_name)
{
if (!implementor_sp)
return UINT32_MAX;
-
- void* implementor = implementor_sp->GetObject();
-
+
+ StructuredData::Generic *generic = implementor_sp->GetAsGeneric();
+ if (!generic)
+ return UINT32_MAX;
+ void *implementor = generic->GetValue();
if (!implementor)
return UINT32_MAX;
@@ -2126,15 +2155,17 @@ ScriptInterpreterPython::GetIndexOfChildWithName (const lldb::ScriptInterpreterO
}
bool
-ScriptInterpreterPython::UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor_sp)
+ScriptInterpreterPython::UpdateSynthProviderInstance(const StructuredData::ObjectSP &implementor_sp)
{
bool ret_val = false;
if (!implementor_sp)
return ret_val;
-
- void* implementor = implementor_sp->GetObject();
-
+
+ StructuredData::Generic *generic = implementor_sp->GetAsGeneric();
+ if (!generic)
+ return ret_val;
+ void *implementor = generic->GetValue();
if (!implementor)
return ret_val;
@@ -2150,15 +2181,17 @@ ScriptInterpreterPython::UpdateSynthProviderInstance (const lldb::ScriptInterpre
}
bool
-ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor_sp)
+ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance(const StructuredData::ObjectSP &implementor_sp)
{
bool ret_val = false;
if (!implementor_sp)
return ret_val;
-
- void* implementor = implementor_sp->GetObject();
-
+
+ StructuredData::Generic *generic = implementor_sp->GetAsGeneric();
+ if (!generic)
+ return ret_val;
+ void *implementor = generic->GetValue();
if (!implementor)
return ret_val;
@@ -2174,15 +2207,17 @@ ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance (const lldb::Scr
}
lldb::ValueObjectSP
-ScriptInterpreterPython::GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor_sp)
+ScriptInterpreterPython::GetSyntheticValue(const StructuredData::ObjectSP &implementor_sp)
{
lldb::ValueObjectSP ret_val(nullptr);
if (!implementor_sp)
return ret_val;
-
- void* implementor = implementor_sp->GetObject();
-
+
+ StructuredData::Generic *generic = implementor_sp->GetAsGeneric();
+ if (!generic)
+ return ret_val;
+ void *implementor = generic->GetValue();
if (!implementor)
return ret_val;
@@ -2440,11 +2475,8 @@ uint64_t replace_all(std::string& str, const std::string& oldStr, const std::str
}
bool
-ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
- bool can_reload,
- bool init_session,
- lldb_private::Error& error,
- lldb::ScriptInterpreterObjectSP* module_sp)
+ScriptInterpreterPython::LoadScriptingModule(const char *pathname, bool can_reload, bool init_session, lldb_private::Error &error,
+ StructuredData::ObjectSP *module_sp)
{
if (!pathname || !pathname[0])
{
@@ -2575,17 +2607,36 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
command_stream.Printf("%s",basename.c_str());
void* module_pyobj = nullptr;
if (ExecuteOneLineWithReturn(command_stream.GetData(),ScriptInterpreter::eScriptReturnTypeOpaqueObject,&module_pyobj) && module_pyobj)
- *module_sp = MakeScriptObject(module_pyobj);
+ module_sp->reset(new StructuredPythonObject(module_pyobj));
}
return true;
}
}
-lldb::ScriptInterpreterObjectSP
-ScriptInterpreterPython::MakeScriptObject (void* object)
+bool
+ScriptInterpreterPython::IsReservedWord (const char* word)
{
- return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterPythonObject(object));
+ if (!word || !word[0])
+ return false;
+
+ llvm::StringRef word_sr(word);
+
+ // filter out a few characters that would just confuse us
+ // and that are clearly not keyword material anyway
+ if (word_sr.find_first_of("'\"") != llvm::StringRef::npos)
+ return false;
+
+ StreamString command_stream;
+ command_stream.Printf("keyword.iskeyword('%s')", word);
+ bool result;
+ ExecuteScriptOptions options;
+ options.SetEnableIO(false);
+ options.SetMaskoutErrors(true);
+ options.SetSetLLDBGlobals(false);
+ if (ExecuteOneLineWithReturn(command_stream.GetData(), ScriptInterpreter::eScriptReturnTypeBool, &result, options))
+ return result;
+ return false;
}
ScriptInterpreterPython::SynchronicityHandler::SynchronicityHandler (lldb::DebuggerSP debugger_sp,
@@ -2663,6 +2714,62 @@ ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function,
return ret_val;
}
+bool
+ScriptInterpreterPython::RunScriptBasedCommand (StructuredData::GenericSP impl_obj_sp,
+ const char* args,
+ ScriptedCommandSynchronicity synchronicity,
+ lldb_private::CommandReturnObject& cmd_retobj,
+ Error& error,
+ const lldb_private::ExecutionContext& exe_ctx)
+{
+ if (!impl_obj_sp || !impl_obj_sp->IsValid())
+ {
+ error.SetErrorString("no function to execute");
+ return false;
+ }
+
+ if (!g_swig_call_command_object)
+ {
+ error.SetErrorString("no helper function to run scripted commands");
+ return false;
+ }
+
+ lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this();
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx));
+
+ if (!debugger_sp.get())
+ {
+ error.SetErrorString("invalid Debugger pointer");
+ return false;
+ }
+
+ bool ret_val = false;
+
+ std::string err_msg;
+
+ {
+ Locker py_lock(this,
+ Locker::AcquireLock | Locker::InitSession | (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN),
+ Locker::FreeLock | Locker::TearDownSession);
+
+ SynchronicityHandler synch_handler(debugger_sp,
+ synchronicity);
+
+ ret_val = g_swig_call_command_object (impl_obj_sp->GetValue(),
+ debugger_sp,
+ args,
+ cmd_retobj,
+ exe_ctx_ref_sp);
+ }
+
+ if (!ret_val)
+ error.SetErrorString("unable to execute script function");
+ else
+ error.Clear();
+
+ return ret_val;
+}
+
// in Python, a special attribute __doc__ contains the docstring
// for an object (function, method, class, ...) if any is defined
// Otherwise, the attribute's value is None
@@ -2695,6 +2802,228 @@ ScriptInterpreterPython::GetDocumentationForItem(const char* item, std::string&
}
}
+bool
+ScriptInterpreterPython::GetShortHelpForCommandObject (StructuredData::GenericSP cmd_obj_sp,
+ std::string& dest)
+{
+ bool got_string = false;
+ dest.clear();
+
+ Locker py_lock (this,
+ Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ static char callee_name[] = "get_short_help";
+
+ if (!cmd_obj_sp)
+ return false;
+
+ PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue();
+
+ if (implementor == nullptr || implementor == Py_None)
+ return false;
+
+ PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ if (pmeth == nullptr || pmeth == Py_None)
+ {
+ Py_XDECREF(pmeth);
+ return false;
+ }
+
+ if (PyCallable_Check(pmeth) == 0)
+ {
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+ return false;
+ }
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+
+ // right now we know this function exists and is callable..
+ PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr);
+
+ // if it fails, print the error but otherwise go on
+ if (PyErr_Occurred())
+ {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ if (py_return != nullptr && py_return != Py_None)
+ {
+ if (PyString_Check(py_return))
+ {
+ dest.assign(PyString_AsString(py_return));
+ got_string = true;
+ }
+ }
+ Py_XDECREF(py_return);
+
+ return got_string;
+}
+
+uint32_t
+ScriptInterpreterPython::GetFlagsForCommandObject (StructuredData::GenericSP cmd_obj_sp)
+{
+ uint32_t result = 0;
+
+ Locker py_lock (this,
+ Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ static char callee_name[] = "get_flags";
+
+ if (!cmd_obj_sp)
+ return result;
+
+ PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue();
+
+ if (implementor == nullptr || implementor == Py_None)
+ return result;
+
+ PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ if (pmeth == nullptr || pmeth == Py_None)
+ {
+ Py_XDECREF(pmeth);
+ return result;
+ }
+
+ if (PyCallable_Check(pmeth) == 0)
+ {
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+ return result;
+ }
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+
+ // right now we know this function exists and is callable..
+ PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr);
+
+ // if it fails, print the error but otherwise go on
+ if (PyErr_Occurred())
+ {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ if (py_return != nullptr && py_return != Py_None)
+ {
+ if (PyInt_Check(py_return))
+ result = (uint32_t)PyInt_AsLong(py_return);
+ else if (PyLong_Check(py_return))
+ result = (uint32_t)PyLong_AsLong(py_return);
+ }
+ Py_XDECREF(py_return);
+
+ return result;
+}
+
+bool
+ScriptInterpreterPython::GetLongHelpForCommandObject (StructuredData::GenericSP cmd_obj_sp,
+ std::string& dest)
+{
+ bool got_string = false;
+ dest.clear();
+
+ Locker py_lock (this,
+ Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ static char callee_name[] = "get_long_help";
+
+ if (!cmd_obj_sp)
+ return false;
+
+ PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue();
+
+ if (implementor == nullptr || implementor == Py_None)
+ return false;
+
+ PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ if (pmeth == nullptr || pmeth == Py_None)
+ {
+ Py_XDECREF(pmeth);
+ return false;
+ }
+
+ if (PyCallable_Check(pmeth) == 0)
+ {
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+ return false;
+ }
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+
+ // right now we know this function exists and is callable..
+ PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr);
+
+ // if it fails, print the error but otherwise go on
+ if (PyErr_Occurred())
+ {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ if (py_return != nullptr && py_return != Py_None)
+ {
+ if (PyString_Check(py_return))
+ {
+ dest.assign(PyString_AsString(py_return));
+ got_string = true;
+ }
+ }
+ Py_XDECREF(py_return);
+
+ return got_string;
+}
+
std::unique_ptr<ScriptInterpreterLocker>
ScriptInterpreterPython::AcquireInterpreterLock ()
{
@@ -2710,6 +3039,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb
SWIGWatchpointCallbackFunction swig_watchpoint_callback,
SWIGPythonTypeScriptCallbackFunction swig_typescript_callback,
SWIGPythonCreateSyntheticProvider swig_synthetic_script,
+ SWIGPythonCreateCommandObject swig_create_cmd,
SWIGPythonCalculateNumChildren swig_calc_children,
SWIGPythonGetChildAtIndex swig_get_child_index,
SWIGPythonGetIndexOfChildWithName swig_get_index_child,
@@ -2719,6 +3049,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb
SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider,
SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider,
SWIGPythonCallCommand swig_call_command,
+ SWIGPythonCallCommandObject swig_call_command_object,
SWIGPythonCallModuleInit swig_call_module_init,
SWIGPythonCreateOSPlugin swig_create_os_plugin,
SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
@@ -2735,6 +3066,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb
g_swig_watchpoint_callback = swig_watchpoint_callback;
g_swig_typescript_callback = swig_typescript_callback;
g_swig_synthetic_script = swig_synthetic_script;
+ g_swig_create_cmd = swig_create_cmd;
g_swig_calc_children = swig_calc_children;
g_swig_get_child_index = swig_get_child_index;
g_swig_get_index_child = swig_get_index_child;
@@ -2744,6 +3076,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb
g_swig_mighthavechildren_provider = swig_mighthavechildren_provider;
g_swig_getvalue_provider = swig_getvalue_provider;
g_swig_call_command = swig_call_command;
+ g_swig_call_command_object = swig_call_command_object;
g_swig_call_module_init = swig_call_module_init;
g_swig_create_os_plugin = swig_create_os_plugin;
g_swig_run_script_keyword_process = swig_run_script_keyword_process;
@@ -2759,11 +3092,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb
void
ScriptInterpreterPython::InitializePrivate ()
{
- static int g_initialized = false;
-
- if (g_initialized)
- return;
-
+ assert(!g_initialized && "ScriptInterpreterPython::InitializePrivate() called more than once!");
g_initialized = true;
Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
@@ -2773,6 +3102,9 @@ ScriptInterpreterPython::InitializePrivate ()
TerminalState stdin_tty_state;
stdin_tty_state.Save(STDIN_FILENO, false);
+#if defined(LLDB_PYTHON_HOME)
+ Py_SetPythonHome(LLDB_PYTHON_HOME);
+#endif
PyGILState_STATE gstate;
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE));
bool threads_already_initialized = false;
@@ -2787,43 +3119,23 @@ ScriptInterpreterPython::InitializePrivate ()
}
Py_InitializeEx (0);
- // Initialize SWIG after setting up python
if (g_swig_init_callback)
g_swig_init_callback ();
// Update the path python uses to search for modules to include the current directory.
PyRun_SimpleString ("import sys");
- PyRun_SimpleString ("sys.path.append ('.')");
-
- // Find the module that owns this code and use that path we get to
- // set the sys.path appropriately.
+ AddToSysPath(AddLocation::End, ".");
FileSpec file_spec;
- char python_dir_path[PATH_MAX];
+ // Don't denormalize paths when calling file_spec.GetPath(). On platforms that use
+ // a backslash as the path separator, this will result in executing python code containing
+ // paths with unescaped backslashes. But Python also accepts forward slashes, so to make
+ // life easier we just use that.
if (HostInfo::GetLLDBPath(ePathTypePythonDir, file_spec))
- {
- std::string python_path("sys.path.insert(0,\"");
- size_t orig_len = python_path.length();
- if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path)))
- {
- python_path.append (python_dir_path);
- python_path.append ("\")");
- PyRun_SimpleString (python_path.c_str());
- python_path.resize (orig_len);
- }
-
- if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, file_spec))
- {
- if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path)))
- {
- python_path.append (python_dir_path);
- python_path.append ("\")");
- PyRun_SimpleString (python_path.c_str());
- python_path.resize (orig_len);
- }
- }
- }
+ AddToSysPath(AddLocation::Beginning, file_spec.GetPath(false));
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, file_spec))
+ AddToSysPath(AddLocation::Beginning, file_spec.GetPath(false));
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");
@@ -2839,6 +3151,28 @@ ScriptInterpreterPython::InitializePrivate ()
stdin_tty_state.Restore();
}
+void
+ScriptInterpreterPython::AddToSysPath(AddLocation location, std::string path)
+{
+ std::string path_copy;
+
+ std::string statement;
+ if (location == AddLocation::Beginning)
+ {
+ statement.assign("sys.path.insert(0,\"");
+ statement.append (path);
+ statement.append ("\")");
+ }
+ else
+ {
+ statement.assign("sys.path.append(\"");
+ statement.append(path);
+ statement.append("\")");
+ }
+ PyRun_SimpleString (statement.c_str());
+}
+
+
//void
//ScriptInterpreterPython::Terminate ()
//{
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
index 42acba232de1..700d223fbc6d 100644
--- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
+++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
@@ -184,13 +184,19 @@ ABIMacOSX_arm::CreateInstance (const ArchSpec &arch)
{
static ABISP g_abi_sp;
const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
- if ((arch_type == llvm::Triple::arm) ||
- (arch_type == llvm::Triple::thumb))
+ const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor();
+
+ if (vendor_type == llvm::Triple::Apple)
{
- if (!g_abi_sp)
- g_abi_sp.reset (new ABIMacOSX_arm);
- return g_abi_sp;
+ if ((arch_type == llvm::Triple::arm) ||
+ (arch_type == llvm::Triple::thumb))
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABIMacOSX_arm);
+ return g_abi_sp;
+ }
}
+
return ABISP();
}
@@ -334,11 +340,11 @@ ABIMacOSX_arm::GetArgumentValues (Thread &thread,
size_t bit_width = 0;
if (clang_type.IsIntegerType (is_signed))
{
- bit_width = clang_type.GetBitSize(nullptr);
+ bit_width = clang_type.GetBitSize(&thread);
}
else if (clang_type.IsPointerOrReferenceType ())
{
- bit_width = clang_type.GetBitSize(nullptr);
+ bit_width = clang_type.GetBitSize(&thread);
}
else
{
@@ -437,7 +443,7 @@ ABIMacOSX_arm::GetReturnValueObjectImpl (Thread &thread,
const RegisterInfo *r0_reg_info = reg_ctx->GetRegisterInfoByName("r0", 0);
if (clang_type.IsIntegerType (is_signed))
{
- size_t bit_width = clang_type.GetBitSize(nullptr);
+ size_t bit_width = clang_type.GetBitSize(&thread);
switch (bit_width)
{
@@ -587,7 +593,7 @@ ABIMacOSX_arm::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
UnwindPlan::RowSP row(new UnwindPlan::Row);
// Our Call Frame Address is the stack pointer value
- row->SetCFARegister (sp_reg_num);
+ row->GetCFAValue().SetIsRegisterPlusOffset (sp_reg_num, 0);
// The previous PC is in the LR
row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
@@ -613,8 +619,7 @@ ABIMacOSX_arm::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
UnwindPlan::RowSP row(new UnwindPlan::Row);
const int32_t ptr_size = 4;
- row->SetCFARegister (fp_reg_num);
- row->SetCFAOffset (2 * ptr_size);
+ row->GetCFAValue().SetIsRegisterPlusOffset (fp_reg_num, 2 * ptr_size);
row->SetOffset (0);
row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
index c2ba165afb4a..04b96180deb3 100644
--- a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
+++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
@@ -219,12 +219,19 @@ ABISP
ABIMacOSX_arm64::CreateInstance (const ArchSpec &arch)
{
static ABISP g_abi_sp;
- if (arch.GetTriple().getArch() == llvm::Triple::aarch64)
+ const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
+ const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor();
+
+ if (vendor_type == llvm::Triple::Apple)
{
- if (!g_abi_sp)
- g_abi_sp.reset (new ABIMacOSX_arm64);
- return g_abi_sp;
+ if (arch_type == llvm::Triple::aarch64)
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABIMacOSX_arm64);
+ return g_abi_sp;
+ }
}
+
return ABISP();
}
@@ -322,11 +329,11 @@ ABIMacOSX_arm64::GetArgumentValues (Thread &thread, ValueList &values) const
size_t bit_width = 0;
if (value_type.IsIntegerType (is_signed))
{
- bit_width = value_type.GetBitSize(nullptr);
+ bit_width = value_type.GetBitSize(&thread);
}
else if (value_type.IsPointerOrReferenceType ())
{
- bit_width = value_type.GetBitSize(nullptr);
+ bit_width = value_type.GetBitSize(&thread);
}
else
{
@@ -562,7 +569,7 @@ ABIMacOSX_arm64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
UnwindPlan::RowSP row(new UnwindPlan::Row);
// Our previous Call Frame Address is the stack pointer
- row->SetCFARegister (sp_reg_num);
+ row->GetCFAValue().SetIsRegisterPlusOffset (sp_reg_num, 0);
// Our previous PC is in the LR
row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
@@ -589,8 +596,7 @@ ABIMacOSX_arm64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
UnwindPlan::RowSP row(new UnwindPlan::Row);
const int32_t ptr_size = 8;
- row->SetCFARegister (fp_reg_num);
- row->SetCFAOffset (2 * ptr_size);
+ row->GetCFAValue().SetIsRegisterPlusOffset (fp_reg_num, 2 * ptr_size);
row->SetOffset (0);
row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
index ee5b9298721b..0853fe286963 100644
--- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
+++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
@@ -552,7 +552,7 @@ ABIMacOSX_i386::GetArgumentValues (Thread &thread,
if (clang_type.IsIntegerType (is_signed))
{
ReadIntegerArgument(value->GetScalar(),
- clang_type.GetBitSize(nullptr),
+ clang_type.GetBitSize(&thread),
is_signed,
thread.GetProcess().get(),
current_stack_argument);
@@ -560,7 +560,7 @@ ABIMacOSX_i386::GetArgumentValues (Thread &thread,
else if (clang_type.IsPointerType())
{
ReadIntegerArgument(value->GetScalar(),
- clang_type.GetBitSize(nullptr),
+ clang_type.GetBitSize(&thread),
false,
thread.GetProcess().get(),
current_stack_argument);
@@ -672,7 +672,7 @@ ABIMacOSX_i386::GetReturnValueObjectImpl (Thread &thread,
if (clang_type.IsIntegerType (is_signed))
{
- size_t bit_width = clang_type.GetBitSize(nullptr);
+ size_t bit_width = clang_type.GetBitSize(&thread);
unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
@@ -746,8 +746,7 @@ ABIMacOSX_i386::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
uint32_t pc_reg_num = dwarf_eip;
UnwindPlan::RowSP row(new UnwindPlan::Row);
- row->SetCFARegister (sp_reg_num);
- row->SetCFAOffset (4);
+ row->GetCFAValue().SetIsRegisterPlusOffset (sp_reg_num, 4);
row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
unwind_plan.AppendRow (row);
@@ -774,8 +773,7 @@ ABIMacOSX_i386::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
UnwindPlan::RowSP row(new UnwindPlan::Row);
const int32_t ptr_size = 4;
- row->SetCFARegister (fp_reg_num);
- row->SetCFAOffset (2 * ptr_size);
+ row->GetCFAValue().SetIsRegisterPlusOffset (fp_reg_num, 2 * ptr_size);
row->SetOffset (0);
row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
diff --git a/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp b/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp
new file mode 100644
index 000000000000..50a9863d83e7
--- /dev/null
+++ b/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp
@@ -0,0 +1,916 @@
+//===-- ABISysV_arm.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_arm.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.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/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/ARM_DWARF_Registers.h"
+#include "Utility/ARM_GCC_Registers.h"
+#include "Plugins/Process/Utility/ARMDefines.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static RegisterInfo g_register_infos[] =
+{
+ // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+ // ========== ======= == === ============= ============ ======================= =================== =========================== ======================= ====================== ========== ===============
+ { "r0", "arg1", 4, 0, eEncodingUint , eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1, gdb_arm_r0, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r1", "arg2", 4, 0, eEncodingUint , eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2, gdb_arm_r1, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r2", "arg3", 4, 0, eEncodingUint , eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3, gdb_arm_r2, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r3", "arg4", 4, 0, eEncodingUint , eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4, gdb_arm_r3, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r4", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r5", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r6", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r7", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, gdb_arm_r7, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, gdb_arm_r11, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "sp", "r13", 4, 0, eEncodingUint , eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "lr", "r14", 4, 0, eEncodingUint , eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "pc", "r15", 4, 0, eEncodingUint , eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "cpsr", "psr", 4, 0, eEncodingUint , eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s0", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s1", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s2", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s3", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s4", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s5", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s6", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s7", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s8", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s9", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s10", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s11", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s12", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s13", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s14", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s15", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s16", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s17", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s18", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s19", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s20", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s21", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s22", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s23", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s24", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s25", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s26", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s27", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s28", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s29", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s30", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s31", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fpscr", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d0", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, gdb_arm_d0, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d1", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, gdb_arm_d1, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d2", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, gdb_arm_d2, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d3", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, gdb_arm_d3, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d4", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, gdb_arm_d4, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d5", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, gdb_arm_d5, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d6", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, gdb_arm_d6, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d7", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, gdb_arm_d7, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d8", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, gdb_arm_d8, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d9", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, gdb_arm_d9, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d10", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, gdb_arm_d10, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d11", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, gdb_arm_d11, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d12", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, gdb_arm_d12, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d13", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, gdb_arm_d13, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d14", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, gdb_arm_d14, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d15", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, gdb_arm_d15, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d16", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, gdb_arm_d16, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d17", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, gdb_arm_d17, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d18", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, gdb_arm_d18, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d19", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, gdb_arm_d19, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d20", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, gdb_arm_d20, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d21", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, gdb_arm_d21, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d22", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, gdb_arm_d22, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d23", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, gdb_arm_d23, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d24", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, gdb_arm_d24, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d25", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, gdb_arm_d25, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d26", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, gdb_arm_d26, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d27", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, gdb_arm_d27, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d28", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, gdb_arm_d28, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d29", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, gdb_arm_d29, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d30", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, gdb_arm_d30, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d31", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, gdb_arm_d31, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r8_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r9_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r10_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r11_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r12_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_usr", "sp_usr", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_usr", "lr_usr", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r8_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r9_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r10_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r11_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r12_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_fiq", "sp_fiq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_fiq", "lr_fiq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_irq", "sp_irq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_irq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_irq", "lr_irq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_irq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_abt", "sp_abt", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_abt, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_abt", "lr_abt", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_abt, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_und", "sp_und", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_und, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_und", "lr_und", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_und, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "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 = llvm::array_lengthof(g_register_infos);
+static bool g_register_info_names_constified = false;
+
+const lldb_private::RegisterInfo *
+ABISysV_arm::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
+ABISysV_arm::GetRedZoneSize () const
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABISysV_arm::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
+ const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor();
+
+ if (vendor_type != llvm::Triple::Apple)
+ {
+ if ((arch_type == llvm::Triple::arm) ||
+ (arch_type == llvm::Triple::thumb))
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABISysV_arm);
+ return g_abi_sp;
+ }
+ }
+
+ return ABISP();
+}
+
+bool
+ABISysV_arm::PrepareTrivialCall (Thread &thread,
+ addr_t sp,
+ addr_t function_addr,
+ addr_t return_addr,
+ llvm::ArrayRef<addr_t> args) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+
+ 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);
+
+ RegisterValue reg_value;
+
+ const uint8_t reg_names[] = { LLDB_REGNUM_GENERIC_ARG1, LLDB_REGNUM_GENERIC_ARG2, LLDB_REGNUM_GENERIC_ARG3, LLDB_REGNUM_GENERIC_ARG4 };
+
+ llvm::ArrayRef<addr_t>::iterator ai = args.begin(), ae = args.end();
+
+ for (size_t i = 0; i < llvm::array_lengthof(reg_names); ++i)
+ {
+ if (ai == ae)
+ break;
+
+ reg_value.SetUInt32(*ai);
+ if (!reg_ctx->WriteRegister(reg_ctx->GetRegisterInfo(eRegisterKindGeneric, reg_names[i]), reg_value))
+ return false;
+
+ ++ai;
+ }
+
+ if (ai != ae)
+ {
+ // Spill onto the stack
+ size_t num_stack_regs = ae - ai;
+
+ sp -= (num_stack_regs * 4);
+ // Keep the stack 8 byte aligned, not that we need to
+ sp &= ~(8ull-1ull);
+
+ // just using arg1 to get the right size
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
+
+ addr_t arg_pos = sp;
+
+ for (; ai != ae; ++ai)
+ {
+ reg_value.SetUInt32(*ai);
+ if (reg_ctx->WriteRegisterValueToMemory(reg_info, arg_pos, reg_info->byte_size, reg_value).Fail())
+ return false;
+ arg_pos += reg_info->byte_size;
+ }
+ }
+
+ TargetSP target_sp (thread.CalculateTarget());
+ Address so_addr;
+
+ // Figure out if our return address is ARM or Thumb by using the
+ // Address::GetCallableLoadAddress(Target*) which will figure out the ARM
+ // thumb-ness and set the correct address bits for us.
+ so_addr.SetLoadAddress (return_addr, target_sp.get());
+ return_addr = so_addr.GetCallableLoadAddress (target_sp.get());
+
+ // Set "lr" to the return address
+ if (!reg_ctx->WriteRegisterFromUnsigned (ra_reg_num, return_addr))
+ return false;
+
+ // Set "sp" to the requested value
+ if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_num, sp))
+ return false;
+
+ // If bit zero or 1 is set, this must be a thumb function, no need to figure
+ // this out from the symbols.
+ so_addr.SetLoadAddress (function_addr, target_sp.get());
+ function_addr = so_addr.GetCallableLoadAddress (target_sp.get());
+
+ const RegisterInfo *cpsr_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+ const uint32_t curr_cpsr = reg_ctx->ReadRegisterAsUnsigned(cpsr_reg_info, 0);
+
+ // Make a new CPSR and mask out any Thumb IT (if/then) bits
+ uint32_t new_cpsr = curr_cpsr & ~MASK_CPSR_IT_MASK;
+ // If bit zero or 1 is set, this must be thumb...
+ if (function_addr & 1ull)
+ new_cpsr |= MASK_CPSR_T; // Set T bit in CPSR
+ else
+ new_cpsr &= ~MASK_CPSR_T; // Clear T bit in CPSR
+
+ if (new_cpsr != curr_cpsr)
+ {
+ if (!reg_ctx->WriteRegisterFromUnsigned (cpsr_reg_info, new_cpsr))
+ return false;
+ }
+
+ function_addr &= ~1ull; // clear bit zero since the CPSR will take care of the mode for us
+
+ // Set "pc" to the address requested
+ if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_num, function_addr))
+ return false;
+
+ return true;
+}
+
+bool
+ABISysV_arm::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ uint32_t num_values = values.GetSize();
+
+
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ // For now, assume that the types in the AST values come from the Target's
+ // scratch AST.
+
+ // 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 clang_type = value->GetClangType();
+ if (clang_type)
+ {
+ bool is_signed = false;
+ size_t bit_width = 0;
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ bit_width = clang_type.GetBitSize(&thread);
+ }
+ else if (clang_type.IsPointerOrReferenceType ())
+ {
+ bit_width = clang_type.GetBitSize(&thread);
+ }
+ else
+ {
+ // We only handle integer, pointer and reference types currently...
+ return false;
+ }
+
+ if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8))
+ {
+ if (value_idx < 4)
+ {
+ // Arguments 1-4 are in r0-r3...
+ const RegisterInfo *arg_reg_info = NULL;
+ arg_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx);
+ if (arg_reg_info)
+ {
+ RegisterValue reg_value;
+
+ if (reg_ctx->ReadRegister(arg_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 it already hasn't been read
+ 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;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+ValueObjectSP
+ABISysV_arm::GetReturnValueObjectImpl (Thread &thread,
+ lldb_private::ClangASTType &clang_type) const
+{
+ Value value;
+ ValueObjectSP return_valobj_sp;
+
+ if (!clang_type)
+ return return_valobj_sp;
+
+ clang::ASTContext *ast_context = clang_type.GetASTContext();
+ if (!ast_context)
+ return return_valobj_sp;
+
+ //value.SetContext (Value::eContextTypeClangType, clang_type.GetOpaqueQualType());
+ value.SetClangType (clang_type);
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return return_valobj_sp;
+
+ bool is_signed;
+ bool is_complex;
+ uint32_t float_count;
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ const RegisterInfo *r0_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
+ size_t bit_width = clang_type.GetBitSize(&thread);
+
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ switch (bit_width)
+ {
+ default:
+ return return_valobj_sp;
+ case 64:
+ {
+ const RegisterInfo *r1_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);
+ uint64_t raw_value;
+ raw_value = reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+ raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r1_reg_info, 0) & UINT32_MAX)) << 32;
+ if (is_signed)
+ value.GetScalar() = (int64_t)raw_value;
+ else
+ value.GetScalar() = (uint64_t)raw_value;
+ }
+ break;
+ case 32:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX);
+ else
+ value.GetScalar() = (uint32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX);
+ break;
+ case 16:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX);
+ else
+ value.GetScalar() = (uint16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX);
+ break;
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX);
+ else
+ value.GetScalar() = (uint8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX);
+ break;
+ }
+ }
+ else if (clang_type.IsPointerType ())
+ {
+ uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+ value.GetScalar() = ptr;
+ }
+ else if (clang_type.IsFloatingPointType(float_count, is_complex))
+ {
+ if (float_count == 1 && !is_complex)
+ {
+ switch (bit_width)
+ {
+ default:
+ return return_valobj_sp;
+ case 64:
+ {
+ static_assert(sizeof(double) == sizeof(uint64_t), "");
+ const RegisterInfo *r1_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);
+ uint64_t raw_value;
+ raw_value = reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+ raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r1_reg_info, 0) & UINT32_MAX)) << 32;
+ value.GetScalar() = *reinterpret_cast<double*>(&raw_value);
+ break;
+ }
+ case 16: // Half precision returned after a conversion to single precision
+ case 32:
+ {
+ static_assert(sizeof(float) == sizeof(uint32_t), "");
+ uint32_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+ value.GetScalar() = *reinterpret_cast<float*>(&raw_value);
+ break;
+ }
+ }
+ }
+ else
+ {
+ // not handled yet
+ return return_valobj_sp;
+ }
+ }
+ else if (clang_type.IsAggregateType())
+ {
+ size_t byte_size = clang_type.GetByteSize(&thread);
+ if (byte_size <= 4)
+ {
+ RegisterValue r0_reg_value;
+ uint32_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+ value.SetBytes(&raw_value, byte_size);
+ }
+ else
+ {
+ RegisterValue r0_reg_value;
+ uint32_t address = reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+
+ Error error;
+ DataBufferHeap buffer(byte_size, 0);
+ thread.GetProcess()->ReadMemory(address, buffer.GetBytes(), buffer.GetByteSize(), error);
+
+ if (error.Success())
+ value.SetBytes(buffer.GetBytes(), buffer.GetByteSize());
+ else
+ return return_valobj_sp;
+ }
+ }
+ else
+ {
+ // not handled yet
+ return return_valobj_sp;
+ }
+
+ // If we get here, we have a valid Value, so make our ValueObject out of it:
+
+ return_valobj_sp = ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ return return_valobj_sp;
+}
+
+Error
+ABISysV_arm::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 clang_type = new_value_sp->GetClangType();
+ if (!clang_type)
+ {
+ error.SetErrorString ("Null clang type for return value.");
+ return error;
+ }
+
+ Thread *thread = frame_sp->GetThread().get();
+
+ bool is_signed;
+ uint32_t count;
+ bool is_complex;
+
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+
+ bool set_it_simple = false;
+ if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType())
+ {
+ DataExtractor 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)
+ {
+ const RegisterInfo *r0_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
+ if (num_bytes <= 4)
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r0_info, raw_value))
+ set_it_simple = true;
+ }
+ else
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, 4);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r0_info, raw_value))
+ {
+ const RegisterInfo *r1_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r1_info, raw_value))
+ set_it_simple = true;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("We don't support returning longer than 64 bit integer values at present.");
+ }
+ }
+ else if (clang_type.IsFloatingPointType (count, is_complex))
+ {
+ if (is_complex)
+ error.SetErrorString ("We don't support returning complex values at present");
+ else
+ error.SetErrorString ("We don't support returning float values at present");
+ }
+
+ if (!set_it_simple)
+ error.SetErrorString ("We only support setting simple integer return types at present.");
+
+ return error;
+}
+
+bool
+ABISysV_arm::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ uint32_t lr_reg_num = dwarf_lr;
+ uint32_t sp_reg_num = dwarf_sp;
+ uint32_t pc_reg_num = dwarf_pc;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ // Our Call Frame Address is the stack pointer value
+ row->GetCFAValue().SetIsRegisterPlusOffset (sp_reg_num, 0);
+
+ // The 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 ("arm at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+
+ return true;
+}
+
+bool
+ABISysV_arm::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear ();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ //TODO: Handle thumb
+ uint32_t fp_reg_num = dwarf_r11;
+ uint32_t pc_reg_num = dwarf_pc;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ const int32_t ptr_size = 4;
+
+ row->GetCFAValue().SetIsRegisterPlusOffset (fp_reg_num, 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 ("arm default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+
+ return true;
+}
+
+// cf. "ARMv6 Function Calling Conventions"
+
+// ARMv7 on GNU/Linux general purpose reg rules:
+// r0-r3 not preserved (used for argument passing)
+// r4-r11 preserved (v1-v8)
+// r12 not presrved
+// r13 preserved (stack pointer)
+// r14 preserved (link register)
+// r15 preserved (pc)
+// cpsr not preserved (different rules for different bits)
+
+// ARMv7 VFP register rules:
+// d0-d7 not preserved (aka s0-s15, q0-q3)
+// d8-d15 preserved (aka s16-s31, q4-q7)
+// d16-d31 not preserved (aka q8-q15)
+
+bool
+ABISysV_arm::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ // Volatile registers are: r0, r1, r2, r3, r9, r12, r13 (aka sp)
+ const char *name = reg_info->name;
+ if (name[0] == 'r')
+ {
+ switch (name[1])
+ {
+ case '0': return name[2] == '\0'; // r0
+ case '1':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // r1
+ case '2':
+ return name[3] == '\0'; // r12
+ default:
+ break;
+ }
+ break;
+
+ case '2': return name[2] == '\0'; // r2
+ case '3': return name[2] == '\0'; // r3
+ default:
+ break;
+ }
+ }
+ else if (name[0] == 'd')
+ {
+ switch (name[1])
+ {
+ case '0':
+ return name[2] == '\0'; // d0 is volatile
+
+ case '1':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // d1 is volatile
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return name[3] == '\0'; // d16 - d19 are volatile
+ default:
+ break;
+ }
+ break;
+
+ case '2':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // d2 is volatile
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return name[3] == '\0'; // d20 - d29 are volatile
+ default:
+ break;
+ }
+ break;
+
+ case '3':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // d3 is volatile
+ case '0':
+ case '1':
+ return name[3] == '\0'; // d30 - d31 are volatile
+ default:
+ break;
+ }
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ return name[2] == '\0'; // d4 - d7 are volatile
+
+ default:
+ break;
+ }
+ }
+ else if (name[0] == 's')
+ {
+ switch (name[1])
+ {
+ case '0':
+ return name[2] == '\0'; // s0 is volatile
+
+ case '1':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // s1 is volatile
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ return name[3] == '\0'; // s10 - s15 are volatile
+ default:
+ break;
+ }
+ break;
+
+ case '2':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // s2 is volatile
+ default:
+ break;
+ }
+ break;
+
+ case '3':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // s3 is volatile
+ default:
+ break;
+ }
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return name[2] == '\0'; // s4 - s9 are volatile
+
+ default:
+ break;
+ }
+ }
+ else if (name[0] == 'q')
+ {
+ switch (name[1])
+ {
+ case '1':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // q1 is volatile
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ return true; // q10-q15 are volatile
+ default:
+ break;
+ };
+ case '0':
+ case '2':
+ case '3':
+ return name[2] == '\0'; // q0-q3 are volatile
+ case '8':
+ case '9':
+ return name[2] == '\0'; // q8-q9 are volatile
+ default:
+ break;
+ }
+ }
+ else if (name[0] == 's' && name[1] == 'p' && name[2] == '\0')
+ return true;
+ }
+ return false;
+}
+
+void
+ABISysV_arm::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "SysV ABI for arm targets",
+ CreateInstance);
+}
+
+void
+ABISysV_arm::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABISysV_arm::GetPluginNameStatic()
+{
+ static ConstString g_name("SysV-arm");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABISysV_arm::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABISysV_arm::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ABI/SysV-arm/ABISysV_arm.h b/source/Plugins/ABI/SysV-arm/ABISysV_arm.h
new file mode 100644
index 000000000000..69becd6ec0c2
--- /dev/null
+++ b/source/Plugins/ABI/SysV-arm/ABISysV_arm.h
@@ -0,0 +1,121 @@
+//===-- ABISysV_arm.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_arm_h_
+#define liblldb_ABISysV_arm_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABISysV_arm : public lldb_private::ABI
+{
+public:
+ ~ABISysV_arm() { }
+
+ size_t
+ GetRedZoneSize () const override;
+
+ bool
+ PrepareTrivialCall (lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t func_addr,
+ lldb::addr_t returnAddress,
+ llvm::ArrayRef<lldb::addr_t> args) const override;
+
+ bool
+ GetArgumentValues (lldb_private::Thread &thread,
+ lldb_private::ValueList &values) const override;
+
+ lldb_private::Error
+ SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) override;
+
+protected:
+ lldb::ValueObjectSP
+ GetReturnValueObjectImpl (lldb_private::Thread &thread,
+ lldb_private::ClangASTType &ast_type) const override;
+
+public:
+ bool
+ CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan) override;
+
+ bool
+ CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan) override;
+
+ bool
+ RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info) override;
+
+ bool
+ CallFrameAddressIsValid (lldb::addr_t cfa) override
+ {
+ // Make sure the stack call frame addresses are are 4 byte aligned
+ if (cfa & (4ull - 1ull))
+ return false; // Not 4 byte aligned
+ if (cfa == 0)
+ return false; // Zero is not a valid stack address
+ return true;
+ }
+
+ bool
+ CodeAddressIsValid (lldb::addr_t pc) override
+ {
+ // Just make sure the address is a valid 32 bit address. Bit zero
+ // might be set due to Thumb function calls, so don't enforce 2 byte
+ // alignment
+ return pc <= UINT32_MAX;
+ }
+
+ lldb::addr_t
+ FixCodeAddress (lldb::addr_t pc) override
+ {
+ // ARM uses bit zero to signify a code address is thumb, so we must
+ // strip bit zero in any code addresses.
+ return pc & ~(lldb::addr_t)1;
+ }
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoArray (uint32_t &count) override;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb::ABISP
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override;
+
+protected:
+private:
+ ABISysV_arm() :
+ lldb_private::ABI()
+ {
+ // Call CreateInstance instead.
+ }
+};
+
+#endif // liblldb_ABISysV_arm_h_
diff --git a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
new file mode 100644
index 000000000000..ed058ff19d99
--- /dev/null
+++ b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
@@ -0,0 +1,1081 @@
+//===-- ABISysV_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 "ABISysV_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/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 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 *
+ABISysV_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
+ABISysV_arm64::GetRedZoneSize () const
+{
+ return 128;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABISysV_arm64::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
+ const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor();
+
+ if (vendor_type != llvm::Triple::Apple)
+ {
+ if (arch_type == llvm::Triple::aarch64)
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABISysV_arm64);
+ return g_abi_sp;
+ }
+ }
+
+ return ABISP();
+}
+
+bool
+ABISysV_arm64::PrepareTrivialCall (Thread &thread,
+ addr_t sp,
+ addr_t func_addr,
+ addr_t return_addr,
+ llvm::ArrayRef<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());
+ }
+
+ // x0 - x7 contain first 8 simple args
+ if (args.size() > 8)
+ 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->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA), return_addr))
+ return false;
+
+ // Set "sp" to the requested value
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP), sp))
+ return false;
+
+ // Set "pc" to the address requested
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC), func_addr))
+ return false;
+
+ return true;
+}
+
+//TODO: We dont support fp/SIMD arguments in v0-v7
+bool
+ABISysV_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(&thread);
+ }
+ else if (value_type.IsPointerOrReferenceType ())
+ {
+ bit_width = value_type.GetBitSize(&thread);
+ }
+ 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-8 are in x0-x7...
+ const RegisterInfo *reg_info = NULL;
+ reg_info= reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx);
+
+ 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
+ {
+ //TODO: Verify for stack layout for SysV
+ 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
+ABISysV_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 & eTypeIsScalar ||
+ type_flags & eTypeIsPointer)
+ {
+ if (type_flags & eTypeIsInteger ||
+ type_flags & 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->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
+ 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->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);
+ 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 & eTypeIsFloat)
+ {
+ if (type_flags & 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 & 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
+ABISysV_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->GetCFAValue().SetIsRegisterPlusOffset (sp_reg_num, 0);
+
+ // 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
+ABISysV_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->GetCFAValue().SetIsRegisterPlusOffset (fp_reg_num, 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 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
+ABISysV_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
+ // Although documentation says only x19-28 + sp are callee saved
+ // We ll also have to treat x30 as non-volatile.
+ // Each dwarf frame has its own value of 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
+ default:
+ return true;
+ }
+ case '3': // x30 (lr) and x31 (sp) treat as non-volatile
+ if (name[2] == '0' || name[2] == '1')
+ return false;
+ default:
+ return true; // all volatile cases not handled above fall here.
+ }
+ }
+ 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(nullptr);
+
+ 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(nullptr);
+ 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;
+
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN);
+ 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;
+
+ reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN);
+ 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
+ABISysV_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(nullptr);
+
+ const uint32_t type_flags = return_clang_type.GetTypeInfo (NULL);
+ if (type_flags & eTypeIsScalar ||
+ type_flags & eTypeIsPointer)
+ {
+ value.SetValueType(Value::eValueTypeScalar);
+
+ bool success = false;
+ if (type_flags & eTypeIsInteger ||
+ type_flags & eTypeIsPointer )
+ {
+ // Extract the register context so we can read arguments from registers
+ if (byte_size <= 8)
+ {
+ const RegisterInfo *x0_reg_info = NULL;
+ x0_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
+ if (x0_reg_info)
+ {
+ uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, 0);
+ const bool is_signed = (type_flags & eTypeIsSigned) != 0;
+ switch (byte_size)
+ {
+ default:
+ break;
+ case 16: // uint128_t
+ // In register x0 and x1
+ {
+ const RegisterInfo *x1_reg_info = NULL;
+ x1_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);
+
+ 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 & eTypeIsFloat)
+ {
+ if (type_flags & 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 & 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 & eTypeIsStructUnion ||
+ type_flags & 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
+ABISysV_arm64::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "SysV ABI for AArch64 targets",
+ CreateInstance);
+}
+
+void
+ABISysV_arm64::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABISysV_arm64::GetPluginNameStatic()
+{
+ static ConstString g_name("SysV-arm64");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+ABISysV_arm64::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABISysV_arm64::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h
new file mode 100644
index 000000000000..08c8682d8fa4
--- /dev/null
+++ b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h
@@ -0,0 +1,125 @@
+//===-- ABISysV_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_ABISysV_arm64_h_
+#define liblldb_ABISysV_arm64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABISysV_arm64 : public lldb_private::ABI
+{
+public:
+ ~ABISysV_arm64() { }
+
+ size_t
+ GetRedZoneSize () const override;
+
+ 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 override;
+
+ bool
+ GetArgumentValues (lldb_private::Thread &thread,
+ lldb_private::ValueList &values) const override;
+
+ lldb_private::Error
+ SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) override;
+
+protected:
+ lldb::ValueObjectSP
+ GetReturnValueObjectImpl (lldb_private::Thread &thread,
+ lldb_private::ClangASTType &ast_type) const override;
+
+public:
+ bool
+ CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan) override;
+
+ bool
+ CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan) override;
+
+ bool
+ RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info) override;
+
+ // 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.
+
+ bool
+ CallFrameAddressIsValid (lldb::addr_t cfa) override
+ {
+ // 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;
+ }
+
+ bool
+ CodeAddressIsValid (lldb::addr_t pc) override
+ {
+ if (pc & (4ull - 1ull))
+ return false; // Not 4 byte aligned
+
+ // Anything else if fair game..
+ return true;
+ }
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoArray (uint32_t &count) override;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb::ABISP
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override;
+
+protected:
+private:
+ ABISysV_arm64() :
+ lldb_private::ABI()
+ {
+ // Call CreateInstance instead.
+ }
+};
+
+#endif // liblldb_ABISysV_arm64_h_
diff --git a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
index 0f01c568ed3e..e9e68bc0e949 100644
--- a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
+++ b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
@@ -263,13 +263,12 @@ ABISysV_hexagon::PrepareTrivialCall ( Thread &thread,
// update the argument with the target pointer
//XXX: This is a gross hack for getting around the const
- *((size_t*)(&arg.value)) = sp;
+ *const_cast<lldb::addr_t*>(&arg.value) = sp;
}
-
#if HEX_ABI_DEBUG
// print the original stack pointer
- printf( "sp : %04lx \n", sp );
+ printf( "sp : %04" PRIx64 " \n", sp );
#endif
// make sure number of parameters matches prototype
@@ -337,7 +336,7 @@ ABISysV_hexagon::PrepareTrivialCall ( Thread &thread,
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 );
+ printf( "\n0x%04" PRIx64 " 0x%08x ", addr, data );
if ( i == 0 ) printf( "<<-- sp" );
}
printf( "\n" );
@@ -385,8 +384,7 @@ ABISysV_hexagon::CreateFunctionEntryUnwindPlan ( UnwindPlan &unwind_plan )
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->GetCFAValue().SetIsRegisterPlusOffset (LLDB_REGNUM_GENERIC_SP, 4);
row->SetOffset(0);
// The previous PC is in the LR
@@ -410,8 +408,7 @@ ABISysV_hexagon::CreateDefaultUnwindPlan ( UnwindPlan &unwind_plan )
UnwindPlan::RowSP row(new UnwindPlan::Row);
- row->SetCFARegister(LLDB_REGNUM_GENERIC_FP);
- row->SetCFAOffset(8);
+ row->GetCFAValue().SetIsRegisterPlusOffset (LLDB_REGNUM_GENERIC_FP, 8);
row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num,-8, true);
row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num,-4, true);
diff --git a/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp b/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp
new file mode 100644
index 000000000000..26da9aeb370d
--- /dev/null
+++ b/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp
@@ -0,0 +1,815 @@
+//===----------------------- ABISysV_i386.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_i386.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/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+// This source file uses the following document as a reference:
+//====================================================================
+// System V Application Binary Interface
+// Intel386 Architecture Processor Supplement, Version 1.0
+// Edited by
+// H.J. Lu, David L Kreitzer, Milind Girkar, Zia Ansari
+//
+// (Based on
+// System V Application Binary Interface,
+// AMD64 Architecture Processor Supplement,
+// Edited by
+// H.J. Lu, Michael Matz, Milind Girkar, Jan Hubicka,
+// Andreas Jaeger, Mark Mitchell)
+//
+// February 3, 2015
+//====================================================================
+
+
+
+// DWARF Register Number Mapping
+// See Table 2.14 of the reference document (specified on top of this file)
+// Comment: Table 2.14 is followed till 'mm' entries.
+// After that, all entries are ignored here.
+
+enum gcc_dwarf_regnums
+{
+ gcc_dwarf_eax = 0,
+ gcc_dwarf_ecx,
+ gcc_dwarf_edx,
+ gcc_dwarf_ebx,
+ gcc_dwarf_esp,
+ gcc_dwarf_ebp,
+ gcc_dwarf_esi,
+ gcc_dwarf_edi,
+ gcc_dwarf_eip,
+ gcc_dwarf_eflags,
+
+ gcc_dwarf_st0 = 11,
+ gcc_dwarf_st1,
+ gcc_dwarf_st2,
+ gcc_dwarf_st3,
+ gcc_dwarf_st4,
+ gcc_dwarf_st5,
+ gcc_dwarf_st6,
+ gcc_dwarf_st7,
+
+ gcc_dwarf_xmm0 = 21,
+ gcc_dwarf_xmm1,
+ gcc_dwarf_xmm2,
+ gcc_dwarf_xmm3,
+ gcc_dwarf_xmm4,
+ gcc_dwarf_xmm5,
+ gcc_dwarf_xmm6,
+ gcc_dwarf_xmm7,
+ gcc_dwarf_ymm0 = gcc_dwarf_xmm0,
+ gcc_dwarf_ymm1 = gcc_dwarf_xmm1,
+ gcc_dwarf_ymm2 = gcc_dwarf_xmm2,
+ gcc_dwarf_ymm3 = gcc_dwarf_xmm3,
+ gcc_dwarf_ymm4 = gcc_dwarf_xmm4,
+ gcc_dwarf_ymm5 = gcc_dwarf_xmm5,
+ gcc_dwarf_ymm6 = gcc_dwarf_xmm6,
+ gcc_dwarf_ymm7 = gcc_dwarf_xmm7,
+
+ gcc_dwarf_mm0 = 29,
+ gcc_dwarf_mm1,
+ gcc_dwarf_mm2,
+ gcc_dwarf_mm3,
+ gcc_dwarf_mm4,
+ gcc_dwarf_mm5,
+ gcc_dwarf_mm6,
+ gcc_dwarf_mm7
+};
+
+
+enum gdb_regnums
+{
+ gdb_eax = 0,
+ gdb_ecx = 1,
+ gdb_edx = 2,
+ gdb_ebx = 3,
+ gdb_esp = 4,
+ gdb_ebp = 5,
+ gdb_esi = 6,
+ gdb_edi = 7,
+ gdb_eip = 8,
+ gdb_eflags = 9,
+ gdb_cs = 10,
+ gdb_ss = 11,
+ gdb_ds = 12,
+ gdb_es = 13,
+ gdb_fs = 14,
+ gdb_gs = 15,
+ gdb_st0 = 16,
+ gdb_st1 = 17,
+ gdb_st2 = 18,
+ gdb_st3 = 19,
+ gdb_st4 = 20,
+ gdb_st5 = 21,
+ gdb_st6 = 22,
+ gdb_st7 = 23,
+ gdb_fctrl = 24, gdb_fcw = gdb_fctrl,
+ gdb_fstat = 25, gdb_fsw = gdb_fstat,
+ gdb_ftag = 26, gdb_ftw = gdb_ftag,
+ gdb_fiseg = 27, gdb_fpu_cs = gdb_fiseg,
+ gdb_fioff = 28, gdb_ip = gdb_fioff,
+ gdb_foseg = 29, gdb_fpu_ds = gdb_foseg,
+ gdb_fooff = 30, gdb_dp = gdb_fooff,
+ gdb_fop = 31,
+ gdb_xmm0 = 32,
+ gdb_xmm1 = 33,
+ gdb_xmm2 = 34,
+ gdb_xmm3 = 35,
+ gdb_xmm4 = 36,
+ gdb_xmm5 = 37,
+ gdb_xmm6 = 38,
+ gdb_xmm7 = 39,
+ gdb_mxcsr = 40,
+ gdb_mm0 = 41,
+ gdb_mm1 = 42,
+ gdb_mm2 = 43,
+ gdb_mm3 = 44,
+ gdb_mm4 = 45,
+ gdb_mm5 = 46,
+ gdb_mm6 = 47,
+ gdb_mm7 = 48,
+ gdb_ymm0 = gdb_xmm0,
+ gdb_ymm1 = gdb_xmm1,
+ gdb_ymm2 = gdb_xmm2,
+ gdb_ymm3 = gdb_xmm3,
+ gdb_ymm4 = gdb_xmm4,
+ gdb_ymm5 = gdb_xmm5,
+ gdb_ymm6 = gdb_xmm6,
+ gdb_ymm7 = gdb_xmm7
+};
+
+
+static RegisterInfo g_register_infos[] =
+{
+ // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+ // ====== ======= == === ============= ============ ===================== ===================== ============================ ==================== ====================== ========== ===============
+ { "eax", nullptr, 4, 0, eEncodingUint , eFormatHex , { gcc_dwarf_eax , gcc_dwarf_eax , LLDB_INVALID_REGNUM , gdb_eax , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ebx" , nullptr, 4, 0, eEncodingUint , eFormatHex , { gcc_dwarf_ebx , gcc_dwarf_ebx , LLDB_INVALID_REGNUM , gdb_ebx , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ecx" , nullptr, 4, 0, eEncodingUint , eFormatHex , { gcc_dwarf_ecx , gcc_dwarf_ecx , LLDB_REGNUM_GENERIC_ARG4 , gdb_ecx , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "edx" , nullptr, 4, 0, eEncodingUint , eFormatHex , { gcc_dwarf_edx , gcc_dwarf_edx , LLDB_REGNUM_GENERIC_ARG3 , gdb_edx , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "esi" , nullptr, 4, 0, eEncodingUint , eFormatHex , { gcc_dwarf_esi , gcc_dwarf_esi , LLDB_REGNUM_GENERIC_ARG2 , gdb_esi , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "edi" , nullptr, 4, 0, eEncodingUint , eFormatHex , { gcc_dwarf_edi , gcc_dwarf_edi , LLDB_REGNUM_GENERIC_ARG1 , gdb_edi , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ebp" , "fp", 4, 0, eEncodingUint , eFormatHex , { gcc_dwarf_ebp , gcc_dwarf_ebp , LLDB_REGNUM_GENERIC_FP , gdb_ebp , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "esp" , "sp", 4, 0, eEncodingUint , eFormatHex , { gcc_dwarf_esp , gcc_dwarf_esp , LLDB_REGNUM_GENERIC_SP , gdb_esp , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "eip" , "pc", 4, 0, eEncodingUint , eFormatHex , { gcc_dwarf_eip , gcc_dwarf_eip , LLDB_REGNUM_GENERIC_PC , gdb_eip , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "eflags", nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_REGNUM_GENERIC_FLAGS , gdb_eflags , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "cs" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_cs , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ss" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ss , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ds" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ds , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "es" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_es , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "fs" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fs , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "gs" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_gs , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "st0" , nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_st0 , LLDB_INVALID_REGNUM , gdb_st0 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "st1" , nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_st1 , LLDB_INVALID_REGNUM , gdb_st1 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "st2" , nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_st2 , LLDB_INVALID_REGNUM , gdb_st2 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "st3" , nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_st3 , LLDB_INVALID_REGNUM , gdb_st3 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "st4" , nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_st4 , LLDB_INVALID_REGNUM , gdb_st4 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "st5" , nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_st5 , LLDB_INVALID_REGNUM , gdb_st5 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "st6" , nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_st6 , LLDB_INVALID_REGNUM , gdb_st6 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "st7" , nullptr, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_st7 , LLDB_INVALID_REGNUM , gdb_st7 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "fctrl" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fctrl , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "fstat" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fstat , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ftag" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ftag , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "fiseg" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fiseg , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "fioff" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fioff , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "foseg" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_foseg , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "fooff" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fooff , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "fop" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fop , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "xmm0" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_xmm0 , LLDB_INVALID_REGNUM , gdb_xmm0 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "xmm1" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_xmm1 , LLDB_INVALID_REGNUM , gdb_xmm1 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "xmm2" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_xmm2 , LLDB_INVALID_REGNUM , gdb_xmm2 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "xmm3" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_xmm3 , LLDB_INVALID_REGNUM , gdb_xmm3 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "xmm4" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_xmm4 , LLDB_INVALID_REGNUM , gdb_xmm4 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "xmm5" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_xmm5 , LLDB_INVALID_REGNUM , gdb_xmm5 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "xmm6" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_xmm6 , LLDB_INVALID_REGNUM , gdb_xmm6 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "xmm7" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_xmm7 , LLDB_INVALID_REGNUM , gdb_xmm7 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "mxcsr" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_mxcsr , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ymm0" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_ymm0 , LLDB_INVALID_REGNUM , gdb_ymm0 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ymm1" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_ymm1 , LLDB_INVALID_REGNUM , gdb_ymm1 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ymm2" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_ymm2 , LLDB_INVALID_REGNUM , gdb_ymm2 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ymm3" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_ymm3 , LLDB_INVALID_REGNUM , gdb_ymm3 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ymm4" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_ymm4 , LLDB_INVALID_REGNUM , gdb_ymm4 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ymm5" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_ymm5 , LLDB_INVALID_REGNUM , gdb_ymm5 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ymm6" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_ymm6 , LLDB_INVALID_REGNUM , gdb_ymm6 , LLDB_INVALID_REGNUM }, nullptr, nullptr},
+ { "ymm7" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , gcc_dwarf_ymm7 , LLDB_INVALID_REGNUM , gdb_ymm7 , LLDB_INVALID_REGNUM }, nullptr, nullptr}
+};
+
+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 *
+ABISysV_i386::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;
+}
+
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABISysV_i386::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ if ((arch.GetTriple().getArch() == llvm::Triple::x86) &&
+ arch.GetTriple().isOSLinux())
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABISysV_i386);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABISysV_i386::PrepareTrivialCall (Thread &thread,
+ addr_t sp,
+ addr_t func_addr,
+ addr_t return_addr,
+ llvm::ArrayRef<addr_t> args) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // While using register info to write a register value to memory, the register info
+ // just needs to have the correct size of a 32 bit register, the actual register it
+ // pertains to is not important, just the size needs to be correct.
+ // "eax" is used here for this purpose.
+ const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
+ if (!reg_info_32)
+ return false; // TODO this should actually never happen
+
+ Error error;
+ RegisterValue reg_value;
+
+ // Make room for the argument(s) on the stack
+ sp -= 4 * args.size();
+
+ // SP Alignment
+ sp &= ~(16ull-1ull); // 16-byte alignment
+
+ // Write arguments onto the stack
+ addr_t arg_pos = sp;
+ for (addr_t arg : args)
+ {
+ reg_value.SetUInt32(arg);
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ arg_pos,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+ arg_pos += 4;
+ }
+
+ // The return address is pushed onto the stack
+ sp -= 4;
+ reg_value.SetUInt32(return_addr);
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+
+ // Setting %esp to the actual stack value.
+ if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_num, sp))
+ return false;
+
+ // Setting %eip to the address of the called function.
+ if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_num, func_addr))
+ return false;
+
+ return true;
+}
+
+
+static bool
+ReadIntegerArgument (Scalar &scalar,
+ unsigned int bit_width,
+ bool is_signed,
+ Process *process,
+ addr_t &current_stack_argument)
+{
+ uint32_t byte_size = (bit_width + (8-1))/8;
+ Error error;
+
+ if (!process)
+ return false;
+
+ if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, is_signed, scalar, error))
+ {
+ current_stack_argument += byte_size;
+ return true;
+ }
+ return false;
+}
+
+
+bool
+ABISysV_i386::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ // Get pointer to the first stack argument
+ addr_t sp = reg_ctx->GetSP(0);
+ if (!sp)
+ return false;
+
+ addr_t current_stack_argument = sp + 4; // jump over return address
+
+ for (value_index = 0;
+ value_index < num_values;
+ ++value_index)
+ {
+ Value *value = values.GetValueAtIndex(value_index);
+
+ if (!value)
+ return false;
+
+ // Currently: Support for extracting values with Clang QualTypes only.
+ ClangASTType clang_type (value->GetClangType());
+ if (clang_type)
+ {
+ bool is_signed;
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(&thread),
+ is_signed,
+ thread.GetProcess().get(),
+ current_stack_argument);
+ }
+ else if (clang_type.IsPointerType())
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(&thread),
+ false,
+ thread.GetProcess().get(),
+ current_stack_argument);
+ }
+ }
+ }
+ return true;
+}
+
+
+
+Error
+ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp)
+{
+ Error error;
+ //ToDo: Yet to be implemented
+ error.SetErrorString("ABISysV_i386::SetReturnValueObject(): Not implemented yet");
+ return error;
+}
+
+
+ValueObjectSP
+ABISysV_i386::GetReturnValueObjectSimple (Thread &thread,
+ ClangASTType &return_clang_type) const
+{
+ ValueObjectSP return_valobj_sp;
+ Value value;
+
+ if (!return_clang_type)
+ return return_valobj_sp;
+
+ value.SetClangType (return_clang_type);
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return return_valobj_sp;
+
+ const uint32_t type_flags = return_clang_type.GetTypeInfo ();
+
+ unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
+ unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
+
+
+ // Following "IF ELSE" block categorizes various 'Fundamental Data Types'.
+ // The terminology 'Fundamental Data Types' used here is adopted from
+ // Table 2.1 of the reference document (specified on top of this file)
+
+ if (type_flags & eTypeIsPointer) // 'Pointer'
+ {
+ uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff ;
+ value.SetValueType(Value::eValueTypeScalar);
+ value.GetScalar() = ptr;
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ }
+
+ else if ((type_flags & eTypeIsScalar) || (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point'
+ {
+ value.SetValueType(Value::eValueTypeScalar);
+ const size_t byte_size = return_clang_type.GetByteSize(nullptr);
+ bool success = false;
+
+ if (type_flags & eTypeIsInteger) // 'Integral' except enum
+ {
+ const bool is_signed = ((type_flags & eTypeIsSigned) != 0);
+ uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff ;
+ raw_value |= (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) & 0xffffffff) << 32;
+
+ switch (byte_size)
+ {
+ default:
+ break;
+
+ case 16:
+ // For clang::BuiltinType::UInt128 & Int128
+ // ToDo: Need to decide how to handle it
+ break ;
+
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int64_t)(raw_value);
+ else
+ value.GetScalar() = (uint64_t)(raw_value);
+ success = true;
+ break;
+
+ case 4:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);
+ else
+ value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);
+ success = true;
+ break;
+
+ case 2:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);
+ else
+ value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);
+ success = true;
+ break;
+
+ case 1:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);
+ else
+ value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);
+ success = true;
+ break;
+ }
+
+ if (success)
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ }
+
+ else if (type_flags & eTypeIsEnumeration) // handles enum
+ {
+ uint32_t enm = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff ;
+ value.SetValueType(Value::eValueTypeScalar);
+ value.GetScalar() = enm;
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ }
+
+ else if (type_flags & eTypeIsFloat) // 'Floating Point'
+ {
+ if (byte_size <= 12) // handles float, double, long double, __float80
+ {
+ const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0);
+ RegisterValue st0_value;
+
+ if (reg_ctx->ReadRegister (st0_info, st0_value))
+ {
+ DataExtractor data;
+ if (st0_value.GetData(data))
+ {
+ lldb::offset_t offset = 0;
+ long double value_long_double = data.GetLongDouble(&offset);
+
+ if (byte_size == 4) // float is 4 bytes
+ {
+ float value_float = (float)value_long_double;
+ value.GetScalar() = value_float;
+ success = true;
+ }
+ else if (byte_size == 8) // double is 8 bytes
+ {
+ // On Android Platform: long double is also 8 bytes
+ // It will be handled here only.
+ double value_double = (double)value_long_double;
+ value.GetScalar() = value_double;
+ success = true;
+ }
+ else if (byte_size == 12) // long double and __float80 are 12 bytes on i386
+ {
+ value.GetScalar() = value_long_double;
+ success = true;
+ }
+ }
+ }
+
+ if (success)
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ }
+ else if(byte_size == 16) // handles __float128
+ {
+ lldb::addr_t storage_addr = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+ return_valobj_sp = ValueObjectMemory::Create (&thread,
+ "",
+ Address (storage_addr, nullptr),
+ return_clang_type);
+ }
+ }
+
+ else // Neither 'Integral' nor 'Floating Point'
+ {
+ // If flow reaches here then check type_flags
+ // This type_flags is unhandled
+ }
+ }
+
+ else if (type_flags & eTypeIsComplex) // 'Complex Floating Point'
+ {
+ // ToDo: Yet to be implemented
+ }
+
+ else if (type_flags & eTypeIsVector) // 'Packed'
+ {
+ const size_t byte_size = return_clang_type.GetByteSize(nullptr);
+ if (byte_size > 0)
+ {
+ const RegisterInfo *vec_reg = reg_ctx->GetRegisterInfoByName("ymm0", 0);
+ if (vec_reg == nullptr)
+ {
+ vec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0);
+ if (vec_reg == nullptr)
+ vec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0);
+ }
+
+ if (vec_reg)
+ {
+ if (byte_size <= vec_reg->byte_size)
+ {
+ ProcessSP process_sp (thread.GetProcess());
+ if (process_sp)
+ {
+ std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0));
+ const ByteOrder byte_order = process_sp->GetByteOrder();
+ RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(vec_reg, reg_value))
+ {
+ Error error;
+ if (reg_value.GetAsMemoryData (vec_reg,
+ heap_data_ap->GetBytes(),
+ heap_data_ap->GetByteSize(),
+ byte_order,
+ error))
+ {
+ DataExtractor data (DataBufferSP (heap_data_ap.release()),
+ byte_order,
+ process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
+ return_valobj_sp = ValueObjectConstResult::Create (&thread,
+ return_clang_type,
+ ConstString(""),
+ data);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ else // 'Decimal Floating Point'
+ {
+ //ToDo: Yet to be implemented
+ }
+ return return_valobj_sp;
+}
+
+
+ValueObjectSP
+ABISysV_i386::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_clang_type) const
+{
+ ValueObjectSP return_valobj_sp;
+
+ if (!return_clang_type)
+ return return_valobj_sp;
+
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ return_valobj_sp = GetReturnValueObjectSimple(thread, return_clang_type);
+ if (return_valobj_sp)
+ return return_valobj_sp;
+
+ RegisterContextSP reg_ctx_sp = thread.GetRegisterContext();
+ if (!reg_ctx_sp)
+ return return_valobj_sp;
+
+ if (return_clang_type.IsAggregateType())
+ {
+ unsigned eax_id = reg_ctx_sp->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
+ lldb::addr_t storage_addr = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+ return_valobj_sp = ValueObjectMemory::Create (&thread,
+ "",
+ Address (storage_addr, nullptr),
+ return_clang_type);
+ }
+
+ return return_valobj_sp;
+}
+
+// This defines CFA as esp+4
+// The saved pc is at CFA-4 (i.e. esp+0)
+// The saved esp is CFA+0
+
+bool
+ABISysV_i386::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ uint32_t sp_reg_num = gcc_dwarf_esp;
+ uint32_t pc_reg_num = gcc_dwarf_eip;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
+ row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("i386 at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ return true;
+}
+
+// This defines CFA as ebp+8
+// The saved pc is at CFA-4 (i.e. ebp+4)
+// The saved ebp is at CFA-8 (i.e. ebp+0)
+// The saved esp is CFA+0
+
+bool
+ABISysV_i386::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ uint32_t fp_reg_num = gcc_dwarf_ebp;
+ uint32_t sp_reg_num = gcc_dwarf_esp;
+ uint32_t pc_reg_num = gcc_dwarf_eip;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ const int32_t ptr_size = 4;
+
+ row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
+ row->SetOffset (0);
+
+ row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
+ row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("i386 default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ return true;
+}
+
+
+// According to "Register Usage" in reference document (specified on top
+// of this source file) ebx, ebp, esi, edi and esp registers are preserved
+// i.e. non-volatile i.e. callee-saved on i386
+bool
+ABISysV_i386::RegisterIsCalleeSaved (const RegisterInfo *reg_info)
+{
+ if (!reg_info)
+ return false;
+
+ // Saved registers are ebx, ebp, esi, edi, esp, eip
+ const char *name = reg_info->name;
+ if (name[0] == 'e')
+ {
+ switch (name[1])
+ {
+ case 'b':
+ if (name[2] == 'x' || name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ case 'd':
+ if (name[2] == 'i')
+ return name[3] == '\0';
+ break;
+ case 'i':
+ if (name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ case 's':
+ if (name[2] == 'i' || name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ }
+ }
+
+ if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
+ return true;
+ if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
+ return true;
+ if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
+ return true;
+
+ return false;
+}
+
+
+void
+ABISysV_i386::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "System V ABI for i386 targets",
+ CreateInstance);
+}
+
+
+void
+ABISysV_i386::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABISysV_i386::GetPluginNameStatic()
+{
+ static ConstString g_name("sysv-i386");
+ return g_name;
+}
+
+
+lldb_private::ConstString
+ABISysV_i386::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
diff --git a/source/Plugins/ABI/SysV-i386/ABISysV_i386.h b/source/Plugins/ABI/SysV-i386/ABISysV_i386.h
new file mode 100644
index 000000000000..9612f900d2ce
--- /dev/null
+++ b/source/Plugins/ABI/SysV-i386/ABISysV_i386.h
@@ -0,0 +1,138 @@
+//===------------------- ABISysV_i386.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_i386_h_
+#define liblldb_ABISysV_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABISysV_i386 :
+ public lldb_private::ABI
+{
+public:
+
+ ~ABISysV_i386()
+ {
+ }
+
+ size_t
+ GetRedZoneSize () const override
+ {
+ return 0; // There is no red zone for i386 Architecture
+ }
+
+ 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 override;
+
+ bool
+ GetArgumentValues (lldb_private::Thread &thread,
+ lldb_private::ValueList &values) const override;
+
+ lldb_private::Error
+ SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) override;
+
+protected:
+ lldb::ValueObjectSP
+ GetReturnValueObjectSimple (lldb_private::Thread &thread,
+ lldb_private::ClangASTType &ast_type) const;
+
+ bool
+ RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info);
+
+public:
+ lldb::ValueObjectSP
+ GetReturnValueObjectImpl (lldb_private::Thread &thread,
+ lldb_private::ClangASTType &type) const override;
+
+ bool
+ CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan) override;
+
+ bool
+ CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan) override;
+
+ bool
+ RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info) override
+ {
+ return !RegisterIsCalleeSaved (reg_info);
+ }
+
+ // The SysV i386 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 (4-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.
+
+ // ToDo: When __m256 arguments are passed then stack frames should be
+ // 32 byte aligned. Decide what to do for 32 byte alignment checking
+ bool
+ CallFrameAddressIsValid (lldb::addr_t cfa) override
+ {
+ // Make sure the stack call frame addresses are 4 byte aligned
+ if (cfa & (4ull - 1ull))
+ return false; // Not 4 byte aligned
+ if (cfa == 0)
+ return false; // Zero is not a valid stack address
+ return true;
+ }
+
+ bool
+ CodeAddressIsValid (lldb::addr_t pc) override
+ {
+ // Check whether the address is a valid 32 bit address
+ return (pc <= UINT32_MAX);
+ }
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoArray (uint32_t &count) override;
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb::ABISP
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+private:
+ ABISysV_i386() : lldb_private::ABI() { } // Call CreateInstance instead.
+};
+
+#endif // liblldb_ABI_h
diff --git a/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp b/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp
new file mode 100644
index 000000000000..e1fc13a691af
--- /dev/null
+++ b/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp
@@ -0,0 +1,590 @@
+//===-- ABISysV_mips.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_mips.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/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum gcc_dwarf_regnums
+{
+ gcc_dwarf_r0 = 0,
+ gcc_dwarf_r1,
+ gcc_dwarf_r2,
+ gcc_dwarf_r3,
+ gcc_dwarf_r4,
+ gcc_dwarf_r5,
+ gcc_dwarf_r6,
+ gcc_dwarf_r7,
+ gcc_dwarf_r8,
+ gcc_dwarf_r9,
+ gcc_dwarf_r10,
+ gcc_dwarf_r11,
+ gcc_dwarf_r12,
+ gcc_dwarf_r13,
+ gcc_dwarf_r14,
+ gcc_dwarf_r15,
+ gcc_dwarf_r16,
+ gcc_dwarf_r17,
+ gcc_dwarf_r18,
+ gcc_dwarf_r19,
+ gcc_dwarf_r20,
+ gcc_dwarf_r21,
+ gcc_dwarf_r22,
+ gcc_dwarf_r23,
+ gcc_dwarf_r24,
+ gcc_dwarf_r25,
+ gcc_dwarf_r26,
+ gcc_dwarf_r27,
+ gcc_dwarf_r28,
+ gcc_dwarf_r29,
+ gcc_dwarf_r30,
+ gcc_dwarf_r31,
+ gcc_dwarf_sr,
+ gcc_dwarf_lo,
+ gcc_dwarf_hi,
+ gcc_dwarf_bad,
+ gcc_dwarf_cause,
+ gcc_dwarf_pc
+};
+
+enum gdb_regnums
+{
+ gdb_r0 = 0,
+ gdb_r1,
+ gdb_r2,
+ gdb_r3,
+ gdb_r4,
+ gdb_r5,
+ gdb_r6,
+ gdb_r7,
+ gdb_r8,
+ gdb_r9,
+ gdb_r10,
+ gdb_r11,
+ gdb_r12,
+ gdb_r13,
+ gdb_r14,
+ gdb_r15,
+ gdb_r16,
+ gdb_r17,
+ gdb_r18,
+ gdb_r19,
+ gdb_r20,
+ gdb_r21,
+ gdb_r22,
+ gdb_r23,
+ gdb_r24,
+ gdb_r25,
+ gdb_r26,
+ gdb_r27,
+ gdb_r28,
+ gdb_r29,
+ gdb_r30,
+ gdb_r31,
+ gdb_sr,
+ gdb_lo,
+ gdb_hi,
+ gdb_bad,
+ gdb_cause,
+ gdb_pc
+};
+
+static const RegisterInfo
+g_register_infos[] =
+{
+ // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+ // ======== ====== == === ============= =================== ============ ===================== ==================== ================= ====================== ========== ===============
+ { "r0" , "zero", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r0, gcc_dwarf_r0, LLDB_INVALID_REGNUM, gdb_r0, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r1" , "AT", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r1, gcc_dwarf_r1, LLDB_INVALID_REGNUM, gdb_r1, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r2" , "v0", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r2, gcc_dwarf_r2, LLDB_INVALID_REGNUM, gdb_r2, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r3" , "v1", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r3, gcc_dwarf_r3, LLDB_INVALID_REGNUM, gdb_r3, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r4" , "arg1", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r4, gcc_dwarf_r4, LLDB_REGNUM_GENERIC_ARG1, gdb_r4, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r5" , "arg2", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r5, gcc_dwarf_r5, LLDB_REGNUM_GENERIC_ARG2, gdb_r5, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r6" , "arg3", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r6, gcc_dwarf_r6, LLDB_REGNUM_GENERIC_ARG3, gdb_r6, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r7" , "arg4", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r7, gcc_dwarf_r7, LLDB_REGNUM_GENERIC_ARG4, gdb_r7, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8" , "arg5", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r8, gcc_dwarf_r8, LLDB_INVALID_REGNUM, gdb_r8, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9" , "arg6", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r9, gcc_dwarf_r9, LLDB_INVALID_REGNUM, gdb_r9, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10" , "arg7", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r10, gcc_dwarf_r10, LLDB_INVALID_REGNUM, gdb_r10, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11" , "arg8", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r11, gcc_dwarf_r11, LLDB_INVALID_REGNUM, gdb_r11, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r12, gcc_dwarf_r12, LLDB_INVALID_REGNUM, gdb_r12, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r13, gcc_dwarf_r13, LLDB_INVALID_REGNUM, gdb_r13, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r14, gcc_dwarf_r14, LLDB_INVALID_REGNUM, gdb_r14, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r15" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r15, gcc_dwarf_r15, LLDB_INVALID_REGNUM, gdb_r15, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r16" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r16, gcc_dwarf_r16, LLDB_INVALID_REGNUM, gdb_r16, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r17" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r17, gcc_dwarf_r17, LLDB_INVALID_REGNUM, gdb_r17, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r18" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r18, gcc_dwarf_r18, LLDB_INVALID_REGNUM, gdb_r18, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r19" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r19, gcc_dwarf_r19, LLDB_INVALID_REGNUM, gdb_r19, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r20" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r20, gcc_dwarf_r20, LLDB_INVALID_REGNUM, gdb_r20, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r21" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r21, gcc_dwarf_r21, LLDB_INVALID_REGNUM, gdb_r21, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r22" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r22, gcc_dwarf_r22, LLDB_INVALID_REGNUM, gdb_r22, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r23" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r23, gcc_dwarf_r23, LLDB_INVALID_REGNUM, gdb_r23, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r24" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r24, gcc_dwarf_r24, LLDB_INVALID_REGNUM, gdb_r24, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r25" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r25, gcc_dwarf_r25, LLDB_INVALID_REGNUM, gdb_r25, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r26" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r26, gcc_dwarf_r26, LLDB_INVALID_REGNUM, gdb_r26, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r27" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r27, gcc_dwarf_r27, LLDB_INVALID_REGNUM, gdb_r27, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r28" , "gp", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r28, gcc_dwarf_r28, LLDB_INVALID_REGNUM, gdb_r28, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r29" , "sp", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r29, gcc_dwarf_r29, LLDB_REGNUM_GENERIC_SP, gdb_r29, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r30" , "fp", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r30, gcc_dwarf_r30, LLDB_REGNUM_GENERIC_FP, gdb_r30, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r31" , "ra", 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r31, gcc_dwarf_r31, LLDB_REGNUM_GENERIC_RA, gdb_r31, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "sr" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_sr, gcc_dwarf_sr, LLDB_REGNUM_GENERIC_FLAGS, gdb_sr, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "lo" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_lo, gcc_dwarf_lo, LLDB_INVALID_REGNUM, gdb_lo, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "hi" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_hi, gcc_dwarf_hi, LLDB_INVALID_REGNUM, gdb_hi, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "bad" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_bad, gcc_dwarf_bad, LLDB_INVALID_REGNUM, gdb_bad, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "cause" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_cause, gcc_dwarf_cause, LLDB_INVALID_REGNUM, gdb_cause, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "pc" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_pc, gcc_dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_pc, LLDB_INVALID_REGNUM }, NULL, NULL},
+};
+
+static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
+
+const lldb_private::RegisterInfo *
+ABISysV_mips::GetRegisterInfoArray (uint32_t &count)
+{
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+size_t
+ABISysV_mips::GetRedZoneSize () const
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABISysV_mips::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
+ if ((arch_type == llvm::Triple::mips) ||
+ (arch_type == llvm::Triple::mipsel))
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABISysV_mips);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABISysV_mips::PrepareTrivialCall (Thread &thread,
+ addr_t sp,
+ addr_t func_addr,
+ addr_t return_addr,
+ llvm::ArrayRef<addr_t> args) const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ StreamString s;
+ s.Printf("ABISysV_mips::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%zd = 0x%" PRIx64, i + 1, args[i]);
+ s.PutCString (")");
+ log->PutCString(s.GetString().c_str());
+ }
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+
+ const RegisterInfo *reg_info = NULL;
+
+ RegisterValue reg_value;
+
+ // Argument registers
+ const char *reg_names[] = { "r4", "r5", "r6", "r7" };
+
+ llvm::ArrayRef<addr_t>::iterator ai = args.begin(), ae = args.end();
+
+ // Write arguments to registers
+ for (size_t i = 0; i < llvm::array_lengthof(reg_names); ++i)
+ {
+ if (ai == ae)
+ break;
+
+ reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);
+ if (log)
+ 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;
+
+ ++ai;
+ }
+
+ // If we have more than 4 arguments --Spill onto the stack
+ if (ai != ae)
+ {
+ // No of arguments to go on stack
+ size_t num_stack_regs = args.size();
+
+ // Allocate needed space for args on the stack
+ sp -= (num_stack_regs * 4);
+
+ // Keep the stack 8 byte aligned
+ sp &= ~(8ull-1ull);
+
+ // just using arg1 to get the right size
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
+
+ addr_t arg_pos = sp+16;
+
+ size_t i = 4;
+ for (; ai != ae; ++ai)
+ {
+ reg_value.SetUInt32(*ai);
+ if (log)
+ log->Printf("About to write arg%zd (0x%" PRIx64 ") at 0x%" PRIx64 "", i+1, args[i], arg_pos);
+
+ if (reg_ctx->WriteRegisterValueToMemory(reg_info, arg_pos, reg_info->byte_size, reg_value).Fail())
+ return false;
+ arg_pos += reg_info->byte_size;
+ i++;
+ }
+ }
+
+ Error error;
+ const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ const RegisterInfo *ra_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+
+ if (log)
+ log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp);
+
+ // Set "sp" to the requested value
+ if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_info, sp))
+ return false;
+
+ if (log)
+ log->Printf("Writing RA: 0x%" PRIx64, (uint64_t)return_addr);
+
+ // Set "ra" to the return address
+ if (!reg_ctx->WriteRegisterFromUnsigned (ra_reg_info, return_addr))
+ return false;
+
+ if (log)
+ log->Printf("Writing PC: 0x%" PRIx64, (uint64_t)func_addr);
+
+ // Set pc to the address of the called function.
+ if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr))
+ return false;
+
+ return true;
+}
+
+bool
+ABISysV_mips::GetArgumentValues (Thread &thread, ValueList &values) const
+{
+ return false;
+}
+
+Error
+ABISysV_mips::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 clang_type = new_value_sp->GetClangType();
+ if (!clang_type)
+ {
+ error.SetErrorString ("Null clang type for return value.");
+ return error;
+ }
+
+ Thread *thread = frame_sp->GetThread().get();
+
+ bool is_signed;
+ uint32_t count;
+ bool is_complex;
+
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+
+ bool set_it_simple = false;
+ if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType())
+ {
+ DataExtractor 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)
+ {
+ const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0);
+ if (num_bytes <= 4)
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r2_info, raw_value))
+ set_it_simple = true;
+ }
+ else
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, 4);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r2_info, raw_value))
+ {
+ const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName("r3", 0);
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r3_info, raw_value))
+ set_it_simple = true;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("We don't support returning longer than 64 bit integer values at present.");
+ }
+ }
+ else if (clang_type.IsFloatingPointType (count, is_complex))
+ {
+ if (is_complex)
+ error.SetErrorString ("We don't support returning complex values at present");
+ else
+ error.SetErrorString ("We don't support returning float values at present");
+ }
+
+ if (!set_it_simple)
+ error.SetErrorString ("We only support setting simple integer return types at present.");
+
+ return error;
+}
+
+
+ValueObjectSP
+ABISysV_mips::GetReturnValueObjectSimple (Thread &thread, ClangASTType &return_clang_type) const
+{
+ ValueObjectSP return_valobj_sp;
+ return return_valobj_sp;
+}
+
+ValueObjectSP
+ABISysV_mips::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_clang_type) const
+{
+ ValueObjectSP return_valobj_sp;
+ Value value;
+
+ if (!return_clang_type)
+ return return_valobj_sp;
+
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ if (exe_ctx.GetTargetPtr() == NULL || exe_ctx.GetProcessPtr() == NULL)
+ return return_valobj_sp;
+
+ value.SetClangType(return_clang_type);
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return return_valobj_sp;
+
+ bool is_signed;
+
+ // In MIPS register "r2" (v0) holds the integer function return values
+ const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoByName("r2", 0);
+
+ if (return_clang_type.IsIntegerType (is_signed))
+ {
+ size_t bit_width = return_clang_type.GetBitSize(&thread);
+
+ switch (bit_width)
+ {
+ default:
+ return return_valobj_sp;
+ case 64:
+ {
+ const RegisterInfo *r3_reg_info = reg_ctx->GetRegisterInfoByName("r3", 0);
+ uint64_t raw_value;
+ raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX;
+ raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r3_reg_info, 0) & UINT32_MAX)) << 32;
+ if (is_signed)
+ value.GetScalar() = (int64_t)raw_value;
+ else
+ value.GetScalar() = (uint64_t)raw_value;
+ }
+ break;
+ case 32:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX);
+ else
+ value.GetScalar() = (uint32_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX);
+ break;
+ case 16:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT16_MAX);
+ else
+ value.GetScalar() = (uint16_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT16_MAX);
+ break;
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT8_MAX);
+ else
+ value.GetScalar() = (uint8_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT8_MAX);
+ break;
+ }
+ }
+ else if (return_clang_type.IsPointerType ())
+ {
+ uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX;
+ value.GetScalar() = ptr;
+ }
+ else
+ {
+ // not handled yet
+ return return_valobj_sp;
+ }
+
+ // If we get here, we have a valid Value, so make our ValueObject out of it:
+
+ return_valobj_sp = ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ return return_valobj_sp;
+}
+
+bool
+ABISysV_mips::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ // Our Call Frame Address is the stack pointer value
+ row->GetCFAValue().SetIsRegisterPlusOffset(gcc_dwarf_r29, 0);
+
+ // The previous PC is in the RA
+ row->SetRegisterLocationToRegister(gcc_dwarf_pc, gcc_dwarf_r31, true);
+ unwind_plan.AppendRow (row);
+
+ // All other registers are the same.
+
+ unwind_plan.SetSourceName ("mips at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetReturnAddressRegister(gcc_dwarf_r31);
+ return true;
+}
+
+bool
+ABISysV_mips::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ row->GetCFAValue().SetIsRegisterPlusOffset(gcc_dwarf_r29, 0);
+
+ row->SetRegisterLocationToRegister(gcc_dwarf_pc, gcc_dwarf_r31, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("mips default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ return true;
+}
+
+bool
+ABISysV_mips::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ return !RegisterIsCalleeSaved (reg_info);
+}
+
+bool
+ABISysV_mips::RegisterIsCalleeSaved (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ // Preserved registers are :
+ // r16-r23, r28, r29, r30, r31
+
+ int reg = ((reg_info->byte_offset) / 4);
+
+ bool save = (reg >= 16) && (reg <= 23);
+ save |= (reg >= 28) && (reg <= 31);
+
+ return save;
+ }
+ return false;
+}
+
+void
+ABISysV_mips::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "System V ABI for mips targets",
+ CreateInstance);
+}
+
+void
+ABISysV_mips::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABISysV_mips::GetPluginNameStatic()
+{
+ static ConstString g_name("sysv-mips");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABISysV_mips::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABISysV_mips::GetPluginVersion()
+{
+ return 1;
+}
diff --git a/source/Plugins/ABI/SysV-mips/ABISysV_mips.h b/source/Plugins/ABI/SysV-mips/ABISysV_mips.h
new file mode 100644
index 000000000000..ad47ac222932
--- /dev/null
+++ b/source/Plugins/ABI/SysV-mips/ABISysV_mips.h
@@ -0,0 +1,123 @@
+//===-- ABISysV_mips.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_mips_h_
+#define liblldb_ABISysV_mips_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABISysV_mips :
+ public lldb_private::ABI
+{
+public:
+
+ ~ABISysV_mips()
+ {
+ }
+
+ 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 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;
+
+ 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
+ CallFrameAddressIsValid (lldb::addr_t cfa)
+ {
+ // Make sure the stack call frame addresses 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)//must- check
+ {
+ if (pc & (4ull - 1ull))
+ return false; // Not 4 byte aligned
+
+ // Anything else if fair game..
+ return true;
+ }
+
+ 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);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ void
+ CreateRegisterMapIfNeeded ();
+
+ bool
+ RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info);
+
+private:
+ ABISysV_mips() : lldb_private::ABI() { } // Call CreateInstance instead.
+};
+
+#endif // liblldb_ABI_h_
diff --git a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp
new file mode 100644
index 000000000000..c790fa7e7bdd
--- /dev/null
+++ b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp
@@ -0,0 +1,570 @@
+//===-- ABISysV_mips64.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_mips64.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/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum gcc_dwarf_regnums
+{
+ gcc_dwarf_r0 = 0,
+ gcc_dwarf_r1,
+ gcc_dwarf_r2,
+ gcc_dwarf_r3,
+ gcc_dwarf_r4,
+ gcc_dwarf_r5,
+ gcc_dwarf_r6,
+ gcc_dwarf_r7,
+ gcc_dwarf_r8,
+ gcc_dwarf_r9,
+ gcc_dwarf_r10,
+ gcc_dwarf_r11,
+ gcc_dwarf_r12,
+ gcc_dwarf_r13,
+ gcc_dwarf_r14,
+ gcc_dwarf_r15,
+ gcc_dwarf_r16,
+ gcc_dwarf_r17,
+ gcc_dwarf_r18,
+ gcc_dwarf_r19,
+ gcc_dwarf_r20,
+ gcc_dwarf_r21,
+ gcc_dwarf_r22,
+ gcc_dwarf_r23,
+ gcc_dwarf_r24,
+ gcc_dwarf_r25,
+ gcc_dwarf_r26,
+ gcc_dwarf_r27,
+ gcc_dwarf_r28,
+ gcc_dwarf_r29,
+ gcc_dwarf_r30,
+ gcc_dwarf_r31,
+ gcc_dwarf_sr,
+ gcc_dwarf_lo,
+ gcc_dwarf_hi,
+ gcc_dwarf_bad,
+ gcc_dwarf_cause,
+ gcc_dwarf_pc
+};
+
+enum gdb_regnums
+{
+ gdb_r0 = 0,
+ gdb_r1,
+ gdb_r2,
+ gdb_r3,
+ gdb_r4,
+ gdb_r5,
+ gdb_r6,
+ gdb_r7,
+ gdb_r8,
+ gdb_r9,
+ gdb_r10,
+ gdb_r11,
+ gdb_r12,
+ gdb_r13,
+ gdb_r14,
+ gdb_r15,
+ gdb_r16,
+ gdb_r17,
+ gdb_r18,
+ gdb_r19,
+ gdb_r20,
+ gdb_r21,
+ gdb_r22,
+ gdb_r23,
+ gdb_r24,
+ gdb_r25,
+ gdb_r26,
+ gdb_r27,
+ gdb_r28,
+ gdb_r29,
+ gdb_r30,
+ gdb_r31,
+ gdb_sr,
+ gdb_lo,
+ gdb_hi,
+ gdb_bad,
+ gdb_cause,
+ gdb_pc
+};
+
+static const RegisterInfo
+g_register_infos_mips64[] =
+{
+ // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+ // ======== ====== == === ============= =================== ============ ===================== ==================== ================= ====================== ========== ===============
+ { "r0" , "zero", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r0, gcc_dwarf_r0, LLDB_INVALID_REGNUM, gdb_r0, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r1" , "AT", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r1, gcc_dwarf_r1, LLDB_INVALID_REGNUM, gdb_r1, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r2" , "v0", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r2, gcc_dwarf_r2, LLDB_INVALID_REGNUM, gdb_r2, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r3" , "v1", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r3, gcc_dwarf_r3, LLDB_INVALID_REGNUM, gdb_r3, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r4" , "arg1", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r4, gcc_dwarf_r4, LLDB_REGNUM_GENERIC_ARG1, gdb_r4, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r5" , "arg2", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r5, gcc_dwarf_r5, LLDB_REGNUM_GENERIC_ARG2, gdb_r5, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r6" , "arg3", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r6, gcc_dwarf_r6, LLDB_REGNUM_GENERIC_ARG3, gdb_r6, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r7" , "arg4", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r7, gcc_dwarf_r7, LLDB_REGNUM_GENERIC_ARG4, gdb_r7, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8" , "arg5", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r8, gcc_dwarf_r8, LLDB_REGNUM_GENERIC_ARG5, gdb_r8, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9" , "arg6", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r9, gcc_dwarf_r9, LLDB_REGNUM_GENERIC_ARG6, gdb_r9, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10" , "arg7", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r10, gcc_dwarf_r10, LLDB_REGNUM_GENERIC_ARG7, gdb_r10, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11" , "arg8", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r11, gcc_dwarf_r11, LLDB_REGNUM_GENERIC_ARG8, gdb_r11, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r12, gcc_dwarf_r12, LLDB_INVALID_REGNUM, gdb_r12, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r13, gcc_dwarf_r13, LLDB_INVALID_REGNUM, gdb_r13, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r14, gcc_dwarf_r14, LLDB_INVALID_REGNUM, gdb_r14, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r15" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r15, gcc_dwarf_r15, LLDB_INVALID_REGNUM, gdb_r15, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r16" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r16, gcc_dwarf_r16, LLDB_INVALID_REGNUM, gdb_r16, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r17" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r17, gcc_dwarf_r17, LLDB_INVALID_REGNUM, gdb_r17, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r18" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r18, gcc_dwarf_r18, LLDB_INVALID_REGNUM, gdb_r18, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r19" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r19, gcc_dwarf_r19, LLDB_INVALID_REGNUM, gdb_r19, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r20" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r20, gcc_dwarf_r20, LLDB_INVALID_REGNUM, gdb_r20, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r21" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r21, gcc_dwarf_r21, LLDB_INVALID_REGNUM, gdb_r21, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r22" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r22, gcc_dwarf_r22, LLDB_INVALID_REGNUM, gdb_r22, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r23" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r23, gcc_dwarf_r23, LLDB_INVALID_REGNUM, gdb_r23, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r24" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r24, gcc_dwarf_r24, LLDB_INVALID_REGNUM, gdb_r24, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r25" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r25, gcc_dwarf_r25, LLDB_INVALID_REGNUM, gdb_r25, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r26" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r26, gcc_dwarf_r26, LLDB_INVALID_REGNUM, gdb_r26, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r27" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r27, gcc_dwarf_r27, LLDB_INVALID_REGNUM, gdb_r27, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r28" , "gp", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r28, gcc_dwarf_r28, LLDB_INVALID_REGNUM, gdb_r28, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r29" , "sp", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r29, gcc_dwarf_r29, LLDB_REGNUM_GENERIC_SP, gdb_r29, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r30" , "fp", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r30, gcc_dwarf_r30, LLDB_REGNUM_GENERIC_FP, gdb_r30, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r31" , "ra", 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_r31, gcc_dwarf_r31, LLDB_REGNUM_GENERIC_RA, gdb_r31, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "sr" , NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_dwarf_sr, gcc_dwarf_sr, LLDB_REGNUM_GENERIC_FLAGS, gdb_sr, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "lo" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_lo, gcc_dwarf_lo, LLDB_INVALID_REGNUM, gdb_lo, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "hi" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_hi, gcc_dwarf_hi, LLDB_INVALID_REGNUM, gdb_hi, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "bad" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_bad, gcc_dwarf_bad, LLDB_INVALID_REGNUM, gdb_bad, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "cause" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_cause, gcc_dwarf_cause, LLDB_INVALID_REGNUM, gdb_cause, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "pc" , NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_pc, gcc_dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_pc, LLDB_INVALID_REGNUM }, NULL, NULL},
+};
+
+static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos_mips64);
+
+const lldb_private::RegisterInfo *
+ABISysV_mips64::GetRegisterInfoArray (uint32_t &count)
+{
+ count = k_num_register_infos;
+ return g_register_infos_mips64;
+}
+
+size_t
+ABISysV_mips64::GetRedZoneSize () const
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABISysV_mips64::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
+ if ((arch_type == llvm::Triple::mips64) ||
+ (arch_type == llvm::Triple::mips64el))
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABISysV_mips64);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABISysV_mips64::PrepareTrivialCall (Thread &thread,
+ addr_t sp,
+ addr_t func_addr,
+ addr_t return_addr,
+ llvm::ArrayRef<addr_t> args) const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ StreamString s;
+ s.Printf("ABISysV_mips64::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%zd = 0x%" PRIx64, i + 1, args[i]);
+ s.PutCString (")");
+ log->PutCString(s.GetString().c_str());
+ }
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+
+ const RegisterInfo *reg_info = NULL;
+
+ if (args.size() > 8) // TODO handle more than 8 arguments
+ return false;
+
+ 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%zd (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
+ return false;
+ }
+
+ // First, align the SP
+
+ if (log)
+ log->Printf("16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, (uint64_t)sp, (uint64_t)(sp & ~0xfull));
+
+ sp &= ~(0xfull); // 16-byte alignment
+
+ Error error;
+ const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ const RegisterInfo *ra_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+
+ if (log)
+ log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp);
+
+ // Set "sp" to the requested value
+ if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_info, sp))
+ return false;
+
+ if (log)
+ log->Printf("Writing RA: 0x%" PRIx64, (uint64_t)return_addr);
+
+ // Set "ra" to the return address
+ if (!reg_ctx->WriteRegisterFromUnsigned (ra_reg_info, return_addr))
+ return false;
+
+ if (log)
+ log->Printf("Writing PC: 0x%" PRIx64, (uint64_t)func_addr);
+
+ // Set pc to the address of the called function.
+ if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr))
+ return false;
+
+ return true;
+}
+
+bool
+ABISysV_mips64::GetArgumentValues (Thread &thread, ValueList &values) const
+{
+ return false;
+}
+
+Error
+ABISysV_mips64::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 clang_type = new_value_sp->GetClangType();
+ if (!clang_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)
+ error.SetErrorString("no registers are available");
+
+ DataExtractor 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;
+ }
+
+ const uint32_t type_flags = clang_type.GetTypeInfo (NULL);
+
+ if (type_flags & eTypeIsScalar ||
+ type_flags & eTypeIsPointer)
+ {
+ if (type_flags & eTypeIsInteger ||
+ type_flags & eTypeIsPointer )
+ {
+ lldb::offset_t offset = 0;
+
+ if (num_bytes <= 16)
+ {
+ const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0);
+ if (num_bytes <= 8)
+ {
+ uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (r2_info, raw_value))
+ error.SetErrorString ("failed to write register r2");
+ }
+ else
+ {
+ uint64_t raw_value = data.GetMaxU64(&offset, 8);
+ if (reg_ctx->WriteRegisterFromUnsigned (r2_info, raw_value))
+ {
+ const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName("r3", 0);
+ raw_value = data.GetMaxU64(&offset, num_bytes - offset);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (r3_info, raw_value))
+ error.SetErrorString ("failed to write register r3");
+ }
+ else
+ error.SetErrorString ("failed to write register r2");
+ }
+ }
+ else
+ {
+ error.SetErrorString("We don't support returning longer than 128 bit integer values at present.");
+ }
+ }
+ else if (type_flags & eTypeIsFloat)
+ {
+ error.SetErrorString("TODO: Handle Float Types.");
+ }
+ }
+ else if (type_flags & eTypeIsVector)
+ {
+ error.SetErrorString("returning vector values are not supported");
+ }
+
+ return error;
+}
+
+
+ValueObjectSP
+ABISysV_mips64::GetReturnValueObjectSimple (Thread &thread, ClangASTType &return_clang_type) const
+{
+ ValueObjectSP return_valobj_sp;
+ return return_valobj_sp;
+}
+
+ValueObjectSP
+ABISysV_mips64::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.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(nullptr);
+ const uint32_t type_flags = return_clang_type.GetTypeInfo (NULL);
+
+ if (type_flags & eTypeIsScalar)
+ {
+ value.SetValueType(Value::eValueTypeScalar);
+
+ bool success = false;
+ if (type_flags & eTypeIsInteger)
+ {
+ // Extract the register context so we can read arguments from registers
+ // In MIPS register "r2" (v0) holds the integer function return values
+
+ uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("r2", 0), 0);
+
+ const bool is_signed = (type_flags & eTypeIsSigned) != 0;
+ switch (byte_size)
+ {
+ default:
+ 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;
+ }
+ }
+
+ if (success)
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ }
+ else if (type_flags & eTypeIsPointer)
+ {
+ value.SetValueType(Value::eValueTypeScalar);
+ uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("r2", 0), 0);
+ value.GetScalar() = (uint64_t)(raw_value);
+
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ }
+ else if (type_flags & eTypeIsVector)
+ {
+ // TODO: Handle vector types
+ }
+ return return_valobj_sp;
+}
+
+bool
+ABISysV_mips64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ // Our Call Frame Address is the stack pointer value
+ row->GetCFAValue().SetIsRegisterPlusOffset(gcc_dwarf_r29, 0);
+
+ // The previous PC is in the RA
+ row->SetRegisterLocationToRegister(gcc_dwarf_pc, gcc_dwarf_r31, true);
+ unwind_plan.AppendRow (row);
+
+ // All other registers are the same.
+
+ unwind_plan.SetSourceName ("mips64 at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetReturnAddressRegister(gcc_dwarf_r31);
+ return true;
+}
+
+bool
+ABISysV_mips64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ row->GetCFAValue().SetIsRegisterPlusOffset(gcc_dwarf_r29, 0);
+
+ row->SetRegisterLocationToRegister(gcc_dwarf_pc, gcc_dwarf_r31, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("mips64 default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ return true;
+}
+
+bool
+ABISysV_mips64::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ return !RegisterIsCalleeSaved (reg_info);
+}
+
+bool
+ABISysV_mips64::RegisterIsCalleeSaved (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ // Preserved registers are :
+ // r16-r23, r28, r29, r30, r31
+
+ int reg = ((reg_info->byte_offset) / 8);
+
+ bool save = (reg >= 16) && (reg <= 23);
+ save |= (reg >= 28) && (reg <= 31);
+
+ return save;
+ }
+ return false;
+}
+
+void
+ABISysV_mips64::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "System V ABI for mips64 targets",
+ CreateInstance);
+}
+
+void
+ABISysV_mips64::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABISysV_mips64::GetPluginNameStatic()
+{
+ static ConstString g_name("sysv-mips64");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABISysV_mips64::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABISysV_mips64::GetPluginVersion()
+{
+ return 1;
+}
diff --git a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h
new file mode 100644
index 000000000000..c37e717e0938
--- /dev/null
+++ b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h
@@ -0,0 +1,133 @@
+//===-- ABISysV_mips64.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_mips64_h_
+#define liblldb_ABISysV_mips64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABISysV_mips64 :
+ public lldb_private::ABI
+{
+public:
+
+ ~ABISysV_mips64()
+ {
+ }
+
+ 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 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;
+
+ 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);
+
+ // The SysV mips 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 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 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);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ void
+ CreateRegisterMapIfNeeded ();
+
+ bool
+ RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info);
+
+private:
+ ABISysV_mips64() : lldb_private::ABI() { } // Call CreateInstance instead.
+};
+
+#endif // liblldb_ABI_h_
diff --git a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp
index 741afebfcb8b..08416dc25b08 100644
--- a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp
+++ b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp
@@ -250,7 +250,7 @@ ABISysV_ppc::PrepareTrivialCall (Thread &thread,
(uint64_t)return_addr);
for (size_t i = 0; i < args.size(); ++i)
- s.Printf (", arg%zd = 0x%" PRIx64, i + 1, args[i]);
+ s.Printf (", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1), args[i]);
s.PutCString (")");
log->PutCString(s.GetString().c_str());
}
@@ -268,7 +268,7 @@ ABISysV_ppc::PrepareTrivialCall (Thread &thread,
{
reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);
if (log)
- log->Printf("About to write arg%zd (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name);
+ log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", static_cast<uint64_t>(i + 1), args[i], reg_info->name);
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
return false;
}
@@ -390,7 +390,7 @@ static bool ReadIntegerArgument(Scalar &scalar,
bool
ABISysV_ppc::GetArgumentValues (Thread &thread,
- ValueList &values) const
+ ValueList &values) const
{
unsigned int num_values = values.GetSize();
unsigned int value_index;
@@ -444,7 +444,7 @@ ABISysV_ppc::GetArgumentValues (Thread &thread,
if (clang_type.IsIntegerType (is_signed))
{
ReadIntegerArgument(value->GetScalar(),
- clang_type.GetBitSize(nullptr),
+ clang_type.GetBitSize(&thread),
is_signed,
thread,
argument_register_ids,
@@ -454,7 +454,7 @@ ABISysV_ppc::GetArgumentValues (Thread &thread,
else if (clang_type.IsPointerType ())
{
ReadIntegerArgument(value->GetScalar(),
- clang_type.GetBitSize(nullptr),
+ clang_type.GetBitSize(&thread),
false,
thread,
argument_register_ids,
@@ -524,7 +524,7 @@ ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjec
error.SetErrorString ("We don't support returning complex values at present");
else
{
- size_t bit_width = clang_type.GetBitSize(nullptr);
+ size_t bit_width = clang_type.GetBitSize(frame_sp.get());
if (bit_width <= 64)
{
DataExtractor data;
@@ -740,7 +740,7 @@ ABISysV_ppc::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_clan
if (!reg_ctx_sp)
return return_valobj_sp;
- const size_t bit_width = return_clang_type.GetBitSize(nullptr);
+ const size_t bit_width = return_clang_type.GetBitSize(&thread);
if (return_clang_type.IsAggregateType())
{
Target *target = exe_ctx.GetTargetPtr();
@@ -782,7 +782,7 @@ ABISysV_ppc::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_clan
uint32_t count;
ClangASTType field_clang_type = return_clang_type.GetFieldAtIndex (idx, name, &field_bit_offset, NULL, NULL);
- const size_t field_bit_width = field_clang_type.GetBitSize(nullptr);
+ const size_t field_bit_width = field_clang_type.GetBitSize(&thread);
// If there are any unaligned fields, this is stored in memory.
if (field_bit_offset % field_bit_width != 0)
@@ -985,7 +985,7 @@ ABISysV_ppc::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
UnwindPlan::RowSP row(new UnwindPlan::Row);
// Our Call Frame Address is the stack pointer value
- row->SetCFARegister (sp_reg_num);
+ row->GetCFAValue().SetIsRegisterPlusOffset (sp_reg_num, 0);
// The previous PC is in the LR
row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
@@ -1011,8 +1011,7 @@ ABISysV_ppc::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
UnwindPlan::RowSP row(new UnwindPlan::Row);
const int32_t ptr_size = 4;
- row->SetCFARegister (sp_reg_num);
- row->SetCFAType(lldb_private::UnwindPlan::Row::CFAIsRegisterDereferenced);
+ row->GetCFAValue().SetIsRegisterDereferenced (sp_reg_num);
row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 1, true);
row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
diff --git a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp
index 88c18fb6f202..eb0d7c00070f 100644
--- a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp
+++ b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp
@@ -250,7 +250,7 @@ ABISysV_ppc64::PrepareTrivialCall (Thread &thread,
(uint64_t)return_addr);
for (size_t i = 0; i < args.size(); ++i)
- s.Printf (", arg%zd = 0x%" PRIx64, i + 1, args[i]);
+ s.Printf (", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1), args[i]);
s.PutCString (")");
log->PutCString(s.GetString().c_str());
}
@@ -268,7 +268,7 @@ ABISysV_ppc64::PrepareTrivialCall (Thread &thread,
{
reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);
if (log)
- log->Printf("About to write arg%zd (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name);
+ log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", static_cast<uint64_t>(i + 1), args[i], reg_info->name);
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
return false;
}
@@ -390,7 +390,7 @@ static bool ReadIntegerArgument(Scalar &scalar,
bool
ABISysV_ppc64::GetArgumentValues (Thread &thread,
- ValueList &values) const
+ ValueList &values) const
{
unsigned int num_values = values.GetSize();
unsigned int value_index;
@@ -444,7 +444,7 @@ ABISysV_ppc64::GetArgumentValues (Thread &thread,
if (clang_type.IsIntegerType (is_signed))
{
ReadIntegerArgument(value->GetScalar(),
- clang_type.GetBitSize(nullptr),
+ clang_type.GetBitSize(&thread),
is_signed,
thread,
argument_register_ids,
@@ -454,7 +454,7 @@ ABISysV_ppc64::GetArgumentValues (Thread &thread,
else if (clang_type.IsPointerType ())
{
ReadIntegerArgument(value->GetScalar(),
- clang_type.GetBitSize(nullptr),
+ clang_type.GetBitSize(&thread),
false,
thread,
argument_register_ids,
@@ -524,7 +524,7 @@ ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObj
error.SetErrorString ("We don't support returning complex values at present");
else
{
- size_t bit_width = clang_type.GetBitSize(nullptr);
+ size_t bit_width = clang_type.GetBitSize(frame_sp.get());
if (bit_width <= 64)
{
DataExtractor data;
@@ -740,7 +740,7 @@ ABISysV_ppc64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_cl
if (!reg_ctx_sp)
return return_valobj_sp;
- const size_t bit_width = return_clang_type.GetBitSize(nullptr);
+ const size_t bit_width = return_clang_type.GetBitSize(&thread);
if (return_clang_type.IsAggregateType())
{
Target *target = exe_ctx.GetTargetPtr();
@@ -782,7 +782,7 @@ ABISysV_ppc64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_cl
uint32_t count;
ClangASTType field_clang_type = return_clang_type.GetFieldAtIndex (idx, name, &field_bit_offset, NULL, NULL);
- const size_t field_bit_width = field_clang_type.GetBitSize(nullptr);
+ const size_t field_bit_width = field_clang_type.GetBitSize(&thread);
// If there are any unaligned fields, this is stored in memory.
if (field_bit_offset % field_bit_width != 0)
@@ -985,7 +985,7 @@ ABISysV_ppc64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
UnwindPlan::RowSP row(new UnwindPlan::Row);
// Our Call Frame Address is the stack pointer value
- row->SetCFARegister (sp_reg_num);
+ row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0);
// The previous PC is in the LR
row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
@@ -1011,8 +1011,7 @@ ABISysV_ppc64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
UnwindPlan::RowSP row(new UnwindPlan::Row);
const int32_t ptr_size = 8;
- row->SetCFARegister (sp_reg_num);
- row->SetCFAType(lldb_private::UnwindPlan::Row::CFAIsRegisterDereferenced);
+ row->GetCFAValue().SetIsRegisterDereferenced(sp_reg_num);
row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 2, true);
row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
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 71d99c8c65d2..1d63628466c2 100644
--- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -318,7 +318,7 @@ ABISysV_x86_64::PrepareTrivialCall (Thread &thread,
(uint64_t)return_addr);
for (size_t i = 0; i < args.size(); ++i)
- s.Printf (", arg%zd = 0x%" PRIx64, i + 1, args[i]);
+ s.Printf (", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1), args[i]);
s.PutCString (")");
log->PutCString(s.GetString().c_str());
}
@@ -336,7 +336,7 @@ ABISysV_x86_64::PrepareTrivialCall (Thread &thread,
{
reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);
if (log)
- log->Printf("About to write arg%zd (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name);
+ log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", static_cast<uint64_t>(i + 1), args[i], reg_info->name);
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
return false;
}
@@ -510,7 +510,7 @@ ABISysV_x86_64::GetArgumentValues (Thread &thread,
if (clang_type.IsIntegerType (is_signed))
{
ReadIntegerArgument(value->GetScalar(),
- clang_type.GetBitSize(nullptr),
+ clang_type.GetBitSize(&thread),
is_signed,
thread,
argument_register_ids,
@@ -520,7 +520,7 @@ ABISysV_x86_64::GetArgumentValues (Thread &thread,
else if (clang_type.IsPointerType ())
{
ReadIntegerArgument(value->GetScalar(),
- clang_type.GetBitSize(nullptr),
+ clang_type.GetBitSize(&thread),
false,
thread,
argument_register_ids,
@@ -590,7 +590,7 @@ ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueOb
error.SetErrorString ("We don't support returning complex values at present");
else
{
- size_t bit_width = clang_type.GetBitSize(nullptr);
+ size_t bit_width = clang_type.GetBitSize(frame_sp.get());
if (bit_width <= 64)
{
const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0);
@@ -821,7 +821,7 @@ ABISysV_x86_64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_c
if (!reg_ctx_sp)
return return_valobj_sp;
- const size_t bit_width = return_clang_type.GetBitSize(nullptr);
+ const size_t bit_width = return_clang_type.GetBitSize(&thread);
if (return_clang_type.IsAggregateType())
{
Target *target = exe_ctx.GetTargetPtr();
@@ -869,8 +869,12 @@ ABISysV_x86_64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_c
uint32_t count;
ClangASTType field_clang_type = return_clang_type.GetFieldAtIndex (idx, name, &field_bit_offset, NULL, NULL);
- const size_t field_bit_width = field_clang_type.GetBitSize(nullptr);
+ const size_t field_bit_width = field_clang_type.GetBitSize(&thread);
+ // if we don't know the size of the field (e.g. invalid type), just bail out
+ if (field_bit_width == 0)
+ break;
+
// If there are any unaligned fields, this is stored in memory.
if (field_bit_offset % field_bit_width != 0)
{
@@ -1084,8 +1088,7 @@ ABISysV_x86_64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
uint32_t pc_reg_num = gcc_dwarf_rip;
UnwindPlan::RowSP row(new UnwindPlan::Row);
- row->SetCFARegister (sp_reg_num);
- row->SetCFAOffset (8);
+ row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 8);
row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -8, false);
row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
unwind_plan.AppendRow (row);
@@ -1112,8 +1115,7 @@ ABISysV_x86_64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
UnwindPlan::RowSP row(new UnwindPlan::Row);
const int32_t ptr_size = 8;
- row->SetCFARegister (gcc_dwarf_rbp);
- row->SetCFAOffset (2 * ptr_size);
+ row->GetCFAValue().SetIsRegisterPlusOffset(gcc_dwarf_rbp, 2 * ptr_size);
row->SetOffset (0);
row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
index 2f9012222c02..75ee8aa4c580 100644
--- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
+++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
@@ -415,7 +415,7 @@ protected:
-DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, unsigned flavor, DisassemblerLLVMC &owner):
+DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, const char *cpu, unsigned flavor, DisassemblerLLVMC &owner):
m_is_valid(true)
{
std::string Error;
@@ -431,7 +431,7 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, uns
std::string features_str;
- m_subtarget_info_ap.reset(curr_target->createMCSubtargetInfo(triple, "",
+ m_subtarget_info_ap.reset(curr_target->createMCSubtargetInfo(triple, cpu,
features_str));
std::unique_ptr<llvm::MCRegisterInfo> reg_info(curr_target->createMCRegInfo(triple));
@@ -469,11 +469,11 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, uns
asm_printer_variant = flavor;
}
- m_instr_printer_ap.reset(curr_target->createMCInstPrinter(asm_printer_variant,
+ m_instr_printer_ap.reset(curr_target->createMCInstPrinter(llvm::Triple{triple},
+ asm_printer_variant,
*m_asm_info_ap.get(),
*m_instr_info_ap.get(),
- *m_reg_info_ap.get(),
- *m_subtarget_info_ap.get()));
+ *m_reg_info_ap.get()));
if (m_instr_printer_ap.get() == NULL)
{
m_disasm_ap.reset();
@@ -518,7 +518,8 @@ DisassemblerLLVMC::LLVMCDisassembler::PrintMCInst (llvm::MCInst &mc_inst,
llvm::StringRef unused_annotations;
llvm::SmallString<64> inst_string;
llvm::raw_svector_ostream inst_stream(inst_string);
- m_instr_printer_ap->printInst (&mc_inst, inst_stream, unused_annotations);
+ m_instr_printer_ap->printInst (&mc_inst, inst_stream, unused_annotations,
+ *m_subtarget_info_ap);
inst_stream.flush();
const size_t output_size = std::min(dst_len - 1, inst_string.size());
std::memcpy(dst, inst_string.data(), output_size);
@@ -533,8 +534,8 @@ DisassemblerLLVMC::LLVMCDisassembler::SetStyle (bool use_hex_immed, HexImmediate
m_instr_printer_ap->setPrintImmHex(use_hex_immed);
switch(hex_style)
{
- case eHexStyleC: m_instr_printer_ap->setPrintImmHex(llvm::HexStyle::C); break;
- case eHexStyleAsm: m_instr_printer_ap->setPrintImmHex(llvm::HexStyle::Asm); break;
+ case eHexStyleC: m_instr_printer_ap->setPrintHexStyle(llvm::HexStyle::C); break;
+ case eHexStyleAsm: m_instr_printer_ap->setPrintHexStyle(llvm::HexStyle::Asm); break;
}
}
@@ -636,7 +637,45 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s
triple = thumb_arch.GetTriple().getTriple().c_str();
}
- m_disasm_ap.reset (new LLVMCDisassembler(triple, flavor, *this));
+ const char *cpu = "";
+
+ switch (arch.GetCore())
+ {
+ case ArchSpec::eCore_mips32:
+ case ArchSpec::eCore_mips32el:
+ cpu = "mips32"; break;
+ case ArchSpec::eCore_mips32r2:
+ case ArchSpec::eCore_mips32r2el:
+ cpu = "mips32r2"; break;
+ case ArchSpec::eCore_mips32r3:
+ case ArchSpec::eCore_mips32r3el:
+ cpu = "mips32r3"; break;
+ case ArchSpec::eCore_mips32r5:
+ case ArchSpec::eCore_mips32r5el:
+ cpu = "mips32r5"; break;
+ case ArchSpec::eCore_mips32r6:
+ case ArchSpec::eCore_mips32r6el:
+ cpu = "mips32r6"; break;
+ case ArchSpec::eCore_mips64:
+ case ArchSpec::eCore_mips64el:
+ cpu = "mips64"; break;
+ case ArchSpec::eCore_mips64r2:
+ case ArchSpec::eCore_mips64r2el:
+ cpu = "mips64r2"; break;
+ case ArchSpec::eCore_mips64r3:
+ case ArchSpec::eCore_mips64r3el:
+ cpu = "mips64r3"; break;
+ case ArchSpec::eCore_mips64r5:
+ case ArchSpec::eCore_mips64r5el:
+ cpu = "mips64r5"; break;
+ case ArchSpec::eCore_mips64r6:
+ case ArchSpec::eCore_mips64r6el:
+ cpu = "mips64r6"; break;
+ default:
+ cpu = ""; break;
+ }
+
+ m_disasm_ap.reset (new LLVMCDisassembler(triple, cpu, flavor, *this));
if (!m_disasm_ap->IsValid())
{
// We use m_disasm_ap.get() to tell whether we are valid or not, so if this isn't good for some reason,
@@ -648,7 +687,7 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s
if (arch.GetTriple().getArch() == llvm::Triple::arm)
{
std::string thumb_triple(thumb_arch.GetTriple().getTriple());
- m_alternate_disasm_ap.reset(new LLVMCDisassembler(thumb_triple.c_str(), flavor, *this));
+ m_alternate_disasm_ap.reset(new LLVMCDisassembler(thumb_triple.c_str(), "", flavor, *this));
if (!m_alternate_disasm_ap->IsValid())
{
m_disasm_ap.reset();
@@ -792,25 +831,63 @@ const char *DisassemblerLLVMC::SymbolLookup (uint64_t value,
//std::string remove_this_prior_to_checkin;
Target *target = m_exe_ctx ? m_exe_ctx->GetTargetPtr() : NULL;
Address value_so_addr;
+ Address pc_so_addr;
if (m_inst->UsingFileAddress())
{
ModuleSP module_sp(m_inst->GetAddress().GetModule());
if (module_sp)
+ {
module_sp->ResolveFileAddress(value, value_so_addr);
+ module_sp->ResolveFileAddress(pc, pc_so_addr);
+ }
}
else if (target && !target->GetSectionLoadList().IsEmpty())
{
target->GetSectionLoadList().ResolveLoadAddress(value, value_so_addr);
+ target->GetSectionLoadList().ResolveLoadAddress(pc, pc_so_addr);
+ }
+
+ SymbolContext sym_ctx;
+ const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ if (pc_so_addr.IsValid() && pc_so_addr.GetModule())
+ {
+ pc_so_addr.GetModule()->ResolveSymbolContextForAddress (pc_so_addr, resolve_scope, sym_ctx);
}
if (value_so_addr.IsValid() && value_so_addr.GetSection())
{
StreamString ss;
- value_so_addr.Dump (&ss,
- target,
- Address::DumpStyleResolvedDescriptionNoFunctionArguments,
- Address::DumpStyleSectionNameOffset);
+ bool format_omitting_current_func_name = false;
+ if (sym_ctx.symbol || sym_ctx.function)
+ {
+ AddressRange range;
+ if (sym_ctx.GetAddressRange (resolve_scope, 0, false, range)
+ && range.GetBaseAddress().IsValid()
+ && range.ContainsLoadAddress (value_so_addr, target))
+ {
+ format_omitting_current_func_name = true;
+ }
+ }
+
+ // If the "value" address (the target address we're symbolicating)
+ // is inside the same SymbolContext as the current instruction pc
+ // (pc_so_addr), don't print the full function name - just print it
+ // with DumpStyleNoFunctionName style, e.g. "<+36>".
+ if (format_omitting_current_func_name)
+ {
+ value_so_addr.Dump (&ss,
+ target,
+ Address::DumpStyleNoFunctionName,
+ Address::DumpStyleSectionNameOffset);
+ }
+ else
+ {
+ value_so_addr.Dump (&ss,
+ target,
+ Address::DumpStyleResolvedDescriptionNoFunctionArguments,
+ Address::DumpStyleSectionNameOffset);
+ }
if (!ss.GetString().empty())
{
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
index 6ab9e9ae2625..4c32e25781d3 100644
--- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
+++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
@@ -41,7 +41,7 @@ class DisassemblerLLVMC : public lldb_private::Disassembler
class LLVMCDisassembler
{
public:
- LLVMCDisassembler (const char *triple, unsigned flavor, DisassemblerLLVMC &owner);
+ LLVMCDisassembler (const char *triple, const char *cpu, unsigned flavor, DisassemblerLLVMC &owner);
~LLVMCDisassembler();
diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
index c79d96abafa2..bbafcf73fa16 100644
--- a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
+++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
@@ -64,7 +64,7 @@ static lldb::addr_t findSymbolAddress( Process *proc, ConstString findName )
if ( ConstString::Compare( findName, symName ) == 0 )
{
- Address addr = sym->GetAddress( );
+ Address addr = sym->GetAddress();
return addr.GetLoadAddress( & proc->GetTarget() );
}
}
@@ -401,7 +401,7 @@ DynamicLoaderHexagonDYLD::RendezvousBreakpointHit(void *baton,
dyld_instance->m_rendezvous.SetRendezvousAddress( structAddr );
if ( log )
- log->Printf( "Found _rtld_debug structure @ 0x%08lx", structAddr );
+ log->Printf( "Found _rtld_debug structure @ 0x%08" PRIx64, structAddr );
}
else
{
diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
index 5035e9d8bb17..61f9b3d441ce 100644
--- a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
+++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
@@ -15,6 +15,7 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
index a504e801daac..8b1dd283394b 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
@@ -16,6 +16,7 @@
#include "lldb/Core/Module.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
@@ -119,9 +120,10 @@ DYLDRendezvous::DYLDRendezvous(Process *process)
Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
if (exe_mod)
{
- exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
+ m_exe_file_spec = exe_mod->GetPlatformFileSpec();
if (log)
- log->Printf ("DYLDRendezvous::%s exe module executable path set: '%s'", __FUNCTION__, m_exe_path);
+ log->Printf ("DYLDRendezvous::%s exe module executable path set: '%s'",
+ __FUNCTION__, m_exe_file_spec.GetCString());
}
else
{
@@ -146,7 +148,7 @@ 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);
+ log->Printf ("DYLDRendezvous::%s address size: %" PRIu64 ", padding %" PRIu64, __FUNCTION__, uint64_t(address_size), uint64_t(padding));
if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
cursor = info_addr = ResolveRendezvousAddress(m_process);
@@ -205,7 +207,12 @@ DYLDRendezvous::UpdateSOEntries()
// state and take a snapshot of the currently loaded images.
if (m_current.state == eAdd || m_current.state == eDelete)
{
- assert(m_previous.state == eConsistent || (m_previous.state == eAdd && m_current.state == eDelete));
+ // Some versions of the android dynamic linker might send two
+ // notifications with state == eAdd back to back. Ignore them
+ // until we get an eConsistent notification.
+ if (!(m_previous.state == eConsistent || (m_previous.state == eAdd && m_current.state == eDelete)))
+ return false;
+
m_soentries.clear();
m_added_soentries.clear();
m_removed_soentries.clear();
@@ -280,8 +287,7 @@ bool
DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry)
{
// On Linux the executable is indicated by an empty path in the entry. On
- // FreeBSD it is the full path to the executable. On Android, it is the
- // basename of the executable.
+ // FreeBSD and on Android it is the full path to the executable.
auto triple = m_process->GetTarget().GetArchitecture().GetTriple();
auto os_type = triple.getOS();
@@ -289,10 +295,14 @@ DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry)
switch (os_type) {
case llvm::Triple::FreeBSD:
- return ::strcmp(entry.path.c_str(), m_exe_path) == 0;
+ return entry.file_spec == m_exe_file_spec;
case llvm::Triple::Linux:
- return entry.path.empty() || (env_type == llvm::Triple::Android &&
- llvm::sys::path::filename(m_exe_path) == entry.path);
+ switch (env_type) {
+ case llvm::Triple::Android:
+ return entry.file_spec == m_exe_file_spec;
+ default:
+ return !entry.file_spec;
+ }
default:
return false;
}
@@ -306,6 +316,9 @@ DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list)
if (m_current.map_addr == 0)
return false;
+ // Clear previous entries since we are about to obtain an up to date list.
+ entry_list.clear();
+
for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
{
if (!ReadSOEntryFromMemory(cursor, entry))
@@ -373,10 +386,11 @@ DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
// FreeBSD and NetBSD (need to validate other OSes).
// http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57
const ArchSpec &arch = m_process->GetTarget().GetArchitecture();
- if (arch.GetCore() == ArchSpec::eCore_mips64)
+ if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD
+ || arch.GetTriple().getOS() == llvm::Triple::NetBSD) &&
+ (arch.GetMachine() == llvm::Triple::mips || arch.GetMachine() == llvm::Triple::mipsel
+ || arch.GetMachine() == llvm::Triple::mips64 || arch.GetMachine() == llvm::Triple::mips64el))
{
- assert (arch.GetTriple().getOS() == llvm::Triple::FreeBSD ||
- arch.GetTriple().getOS() == llvm::Triple::NetBSD);
addr_t mips_l_offs;
if (!(addr = ReadPointer(addr, &mips_l_offs)))
return false;
@@ -395,9 +409,23 @@ DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
if (!(addr = ReadPointer(addr, &entry.prev)))
return false;
-
- entry.path = ReadStringFromMemory(entry.path_addr);
-
+
+ std::string file_path = ReadStringFromMemory(entry.path_addr);
+ entry.file_spec.SetFile(file_path, false);
+
+ // On Android L (5.0, 5.1) the load address of the "/system/bin/linker" isn't filled in
+ // correctly. To get the correct load address we fetch the load address of the file from the
+ // proc file system.
+ if (arch.GetTriple().getEnvironment() == llvm::Triple::Android && entry.base_addr == 0 &&
+ (file_path == "/system/bin/linker" || file_path == "/system/bin/linker64"))
+ {
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ bool is_loaded = false;
+ Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr);
+ if (error.Success() && is_loaded)
+ entry.base_addr = load_addr;
+ }
+
return true;
}
@@ -473,7 +501,7 @@ DYLDRendezvous::DumpToLog(Log *log) const
for (int i = 1; I != E; ++I, ++i)
{
- log->Printf("\n SOEntry [%d] %s", i, I->path.c_str());
+ log->Printf("\n SOEntry [%d] %s", i, I->file_spec.GetCString());
log->Printf(" Base : %" PRIx64, I->base_addr);
log->Printf(" Path : %" PRIx64, I->path_addr);
log->Printf(" Dyn : %" PRIx64, I->dyn_addr);
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
index 51fcd9b7d397..ec5af945ee7b 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
@@ -18,6 +18,7 @@
// Other libraries and framework includes
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"
+#include "lldb/Host/FileSpec.h"
namespace lldb_private {
class Process;
@@ -142,18 +143,18 @@ public:
/// 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.
+ 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.
+ lldb_private::FileSpec file_spec; ///< File spec of shared object.
SOEntry() { clear(); }
bool operator ==(const SOEntry &entry) {
- return this->path == entry.path;
+ return file_spec == entry.file_spec;
}
void clear() {
@@ -163,7 +164,7 @@ public:
dyn_addr = 0;
next = 0;
prev = 0;
- path.clear();
+ file_spec.Clear();
}
};
@@ -190,8 +191,8 @@ public:
protected:
lldb_private::Process *m_process;
- // Cached copy of executable pathname
- char m_exe_path[PATH_MAX];
+ // Cached copy of executable file spec
+ lldb_private::FileSpec m_exe_file_spec;
/// Location of the r_debug structure in the inferiors address space.
lldb::addr_t m_rendezvous_addr;
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index fdef1026f3c6..6330b42ca14a 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -14,6 +14,7 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Target/Platform.h"
#include "lldb/Core/Section.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Process.h"
@@ -119,24 +120,41 @@ DynamicLoaderPOSIXDYLD::DidAttach()
if (log)
log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reloaded auxv data", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID);
- ModuleSP executable_sp = GetTargetExecutable();
- ModuleSpec process_module_spec;
- if (GetProcessModuleSpec(process_module_spec))
- {
- if (executable_sp == nullptr || !executable_sp->MatchesModuleSpec(process_module_spec))
- {
- executable_sp.reset(new Module(process_module_spec));
- assert(m_process != nullptr);
- m_process->GetTarget().SetExecutableModule(executable_sp, false);
- }
- }
+ // ask the process if it can load any of its own modules
+ m_process->LoadModules ();
+
+ ModuleSP executable_sp = GetTargetExecutable ();
+ ResolveExecutableModule (executable_sp);
- addr_t load_offset = ComputeLoadOffset();
+ // find the main process load offset
+ addr_t load_offset = ComputeLoadOffset ();
if (log)
log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " executable '%s', load_offset 0x%" PRIx64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, executable_sp ? executable_sp->GetFileSpec().GetPath().c_str () : "<null executable>", load_offset);
+ // if we dont have a load address we cant re-base
+ bool rebase_exec = (load_offset == LLDB_INVALID_ADDRESS) ? false : true;
+
+ // if we have a valid executable
+ if (executable_sp.get())
+ {
+ lldb_private::ObjectFile * obj = executable_sp->GetObjectFile();
+ if (obj)
+ {
+ // don't rebase if the module already has a load address
+ Target & target = m_process->GetTarget ();
+ Address addr = obj->GetImageInfoAddress (&target);
+ if (addr.GetLoadAddress (&target) != LLDB_INVALID_ADDRESS)
+ rebase_exec = false;
+ }
+ }
+ else
+ {
+ // no executable, nothing to re-base
+ rebase_exec = false;
+ }
- if (executable_sp && load_offset != LLDB_INVALID_ADDRESS)
+ // if the target executable should be re-based
+ if (rebase_exec)
{
ModuleList module_list;
@@ -396,8 +414,7 @@ DynamicLoaderPOSIXDYLD::RefreshModules()
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);
+ ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr);
if (module_sp.get())
{
loaded_modules.AppendIfNeeded(module_sp);
@@ -414,9 +431,8 @@ DynamicLoaderPOSIXDYLD::RefreshModules()
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 =
+ ModuleSpec module_spec{I->file_spec};
+ ModuleSP module_sp =
loaded_modules.FindFirstModule (module_spec);
if (module_sp.get())
@@ -507,9 +523,7 @@ DynamicLoaderPOSIXDYLD::LoadAllCurrentModules()
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);
+ ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr);
if (module_sp.get())
{
module_list.Append(module_sp);
@@ -519,7 +533,7 @@ DynamicLoaderPOSIXDYLD::LoadAllCurrentModules()
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
if (log)
log->Printf("DynamicLoaderPOSIXDYLD::%s failed loading module %s at 0x%" PRIx64,
- __FUNCTION__, module_path, I->base_addr);
+ __FUNCTION__, I->file_spec.GetCString(), I->base_addr);
}
}
@@ -625,17 +639,45 @@ DynamicLoaderPOSIXDYLD::GetThreadLocalData (const lldb::ModuleSP module, const l
return tls_block;
}
-bool
-DynamicLoaderPOSIXDYLD::GetProcessModuleSpec (ModuleSpec& module_spec)
+void
+DynamicLoaderPOSIXDYLD::ResolveExecutableModule (lldb::ModuleSP &module_sp)
{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
if (m_process == nullptr)
- return false;
+ return;
+
+ auto &target = m_process->GetTarget ();
+ const auto platform_sp = target.GetPlatform ();
- auto& target = m_process->GetTarget ();
ProcessInstanceInfo process_info;
- if (!target.GetPlatform ()->GetProcessInfo (m_process->GetID (), process_info))
- return false;
+ if (!platform_sp->GetProcessInfo (m_process->GetID (), process_info))
+ {
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s - failed to get process info for pid %" PRIu64,
+ __FUNCTION__, m_process->GetID ());
+ return;
+ }
+
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s",
+ __FUNCTION__, m_process->GetID (), process_info.GetExecutableFile ().GetPath ().c_str ());
+
+ ModuleSpec module_spec (process_info.GetExecutableFile (), process_info.GetArchitecture ());
+ if (module_sp && module_sp->MatchesModuleSpec (module_spec))
+ return;
+
+ auto error = platform_sp->ResolveExecutable (module_spec, module_sp, nullptr);
+ if (error.Fail ())
+ {
+ StreamString stream;
+ module_spec.Dump (stream);
+
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s - failed to resolve executable with module spec \"%s\": %s",
+ __FUNCTION__, stream.GetString ().c_str (), error.AsCString ());
+ return;
+ }
- module_spec = ModuleSpec (process_info.GetExecutableFile (), process_info.GetArchitecture ());
- return true;
+ target.SetExecutableModule (module_sp, false);
}
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
index 747ff3f2be36..68d3059cb4be 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
@@ -168,9 +168,9 @@ protected:
lldb::addr_t
GetEntryPoint();
- /// Loads ModuleSpec data from inferior process.
- bool
- GetProcessModuleSpec(lldb_private::ModuleSpec& module_spec);
+ /// Loads Module from inferior process.
+ void
+ ResolveExecutableModule(lldb::ModuleSP &module_sp);
private:
DISALLOW_COPY_AND_ASSIGN(DynamicLoaderPOSIXDYLD);
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
index bc358a985248..95ae549e0e4b 100644
--- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
@@ -290,6 +290,9 @@ EmulateInstructionARM::GetRegisterInfo (lldb::RegisterKind reg_kind, uint32_t re
uint32_t
EmulateInstructionARM::GetFramePointerRegisterNumber () const
{
+ if (m_arch.GetTriple().getEnvironment() == llvm::Triple::Android)
+ return LLDB_INVALID_REGNUM; // Don't use frame pointer on android
+
bool is_apple = false;
if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple)
is_apple = true;
@@ -660,9 +663,12 @@ EmulateInstructionARM::EmulateADDRdSPImm (const uint32_t opcode, const ARMEncodi
}
addr_t sp_offset = imm32;
addr_t addr = sp + sp_offset; // a pointer to the stack area
-
+
EmulateInstruction::Context context;
- context.type = eContextSetFramePointer;
+ if (Rd == GetFramePointerRegisterNumber())
+ context.type = eContextSetFramePointer;
+ else
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
RegisterInfo sp_reg;
GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
context.SetRegisterPlusOffset (sp_reg, sp_offset);
@@ -809,13 +815,16 @@ EmulateInstructionARM::EmulateMOVRdRm (const uint32_t opcode, const ARMEncoding
uint32_t result = ReadCoreReg(Rm, &success);
if (!success)
return false;
-
+
// The context specifies that Rm is to be moved into Rd.
EmulateInstruction::Context context;
- context.type = EmulateInstruction::eContextRegisterLoad;
+ if (Rd == 13)
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ else
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
RegisterInfo dwarf_reg;
GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
- context.SetRegister (dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, 0);
if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags))
return false;
@@ -1333,53 +1342,86 @@ EmulateInstructionARM::EmulateADDSPImm (const uint32_t opcode, const ARMEncoding
return false;
uint32_t imm32; // the immediate operand
uint32_t d;
- //bool setflags = false; // Add this back if/when support eEncodingT3 eEncodingA1
- switch (encoding)
+ bool setflags;
+ switch (encoding)
{
case eEncodingT1:
// d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm8:'00', 32);
d = Bits32 (opcode, 10, 8);
imm32 = (Bits32 (opcode, 7, 0) << 2);
-
+ setflags = false;
break;
-
+
case eEncodingT2:
// d = 13; setflags = FALSE; imm32 = ZeroExtend(imm7:'00', 32);
d = 13;
- imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
-
+ imm32 = ThumbImm7Scaled (opcode); // imm32 = ZeroExtend(imm7:'00', 32)
+ setflags = false;
break;
-
+
+ case eEncodingT3:
+ // d = UInt(Rd); setflags = (S == "1"); imm32 = ThumbExpandImm(i:imm3:imm8);
+ d = Bits32 (opcode, 11, 8);
+ imm32 = ThumbExpandImm (opcode);
+ setflags = Bit32 (opcode, 20);
+
+ // if Rd == "1111" && S == "1" then SEE CMN (immediate);
+ if (d == 15 && setflags == 1)
+ return false; // CMN (immediate) not yet supported
+
+ // if d == 15 && S == "0" then UNPREDICTABLE;
+ if (d == 15 && setflags == 0)
+ return false;
+ break;
+
+ case eEncodingT4:
+ {
+ // if Rn == '1111' then SEE ADR;
+ // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(i:imm3:imm8, 32);
+ d = Bits32 (opcode, 11, 8);
+ setflags = false;
+ uint32_t i = Bit32 (opcode, 26);
+ uint32_t imm3 = Bits32 (opcode, 14, 12);
+ uint32_t imm8 = Bits32 (opcode, 7, 0);
+ imm32 = (i << 11) | (imm3 << 8) | imm8;
+
+ // if d == 15 then UNPREDICTABLE;
+ if (d == 15)
+ return false;
+ }
+ break;
+
default:
return false;
}
- addr_t sp_offset = imm32;
- addr_t addr = sp + sp_offset; // the adjusted stack pointer value
-
+ // (result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
+ AddWithCarryResult res = AddWithCarry (sp, imm32, 0);
+
EmulateInstruction::Context context;
- context.type = EmulateInstruction::eContextAdjustStackPointer;
+ if (d == 13)
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ else
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+
RegisterInfo sp_reg;
GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
- context.SetRegisterPlusOffset (sp_reg, sp_offset);
-
+ context.SetRegisterPlusOffset (sp_reg, res.result - sp);
+
if (d == 15)
{
- if (!ALUWritePC (context, addr))
+ if (!ALUWritePC (context, res.result))
return false;
}
else
{
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, addr))
+ // R[d] = result;
+ // if setflags then
+ // APSR.N = result<31>;
+ // APSR.Z = IsZeroBit(result);
+ // APSR.C = carry;
+ // APSR.V = overflow;
+ if (!WriteCoreRegOptionalFlags (context, res.result, d, setflags, res.carry_out, res.overflow))
return false;
-
- // Add this back if/when support eEncodingT3 eEncodingA1
- //if (setflags)
- //{
- // APSR.N = result<31>;
- // APSR.Z = IsZeroBit(result);
- // APSR.C = carry;
- // APSR.V = overflow;
- //}
}
}
return true;
@@ -1496,6 +1538,7 @@ EmulateInstructionARM::EmulateBLXImmediate (const uint32_t opcode, const ARMEnco
uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
imm32 = llvm::SignExtend32<25>(imm25);
target = pc + imm32;
+ SelectInstrSet (eModeThumb);
context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
if (InITBlock() && !LastInITBlock())
return false;
@@ -1514,6 +1557,7 @@ EmulateInstructionARM::EmulateBLXImmediate (const uint32_t opcode, const ARMEnco
uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2);
imm32 = llvm::SignExtend32<25>(imm25);
target = Align(pc, 4) + imm32;
+ SelectInstrSet (eModeARM);
context.SetISAAndImmediateSigned (eModeARM, 4 + imm32);
if (InITBlock() && !LastInITBlock())
return false;
@@ -1523,12 +1567,14 @@ EmulateInstructionARM::EmulateBLXImmediate (const uint32_t opcode, const ARMEnco
lr = pc - 4; // return address
imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
target = Align(pc, 4) + imm32;
+ SelectInstrSet (eModeARM);
context.SetISAAndImmediateSigned (eModeARM, 8 + imm32);
break;
case eEncodingA2:
lr = pc - 4; // return address
imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | Bits32(opcode, 24, 24) << 1);
target = pc + imm32;
+ SelectInstrSet (eModeThumb);
context.SetISAAndImmediateSigned (eModeThumb, 8 + imm32);
break;
default:
@@ -1538,6 +1584,9 @@ EmulateInstructionARM::EmulateBLXImmediate (const uint32_t opcode, const ARMEnco
return false;
if (!BranchWritePC(context, target))
return false;
+ if (m_opcode_cpsr != m_new_inst_cpsr)
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
+ return false;
}
return true;
}
@@ -2301,13 +2350,16 @@ EmulateInstructionARM::EmulateB (const uint32_t opcode, const ARMEncoding encodi
context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
break;
case eEncodingT2:
- imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0));
+ imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0) << 1);
target = pc + imm32;
context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
break;
case eEncodingT3:
// The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
{
+ if (Bits32(opcode, 25, 23) == 7)
+ return false; // See Branches and miscellaneous control on page A6-235.
+
uint32_t S = Bit32(opcode, 26);
uint32_t imm6 = Bits32(opcode, 21, 16);
uint32_t J1 = Bit32(opcode, 13);
@@ -2387,7 +2439,7 @@ EmulateInstructionARM::EmulateCB (const uint32_t opcode, const ARMEncoding encod
default:
return false;
}
- if (nonzero ^ (reg_val == 0))
+ if (m_ignore_conditions || (nonzero ^ (reg_val == 0)))
if (!BranchWritePC(context, target))
return false;
@@ -2417,55 +2469,58 @@ EmulateInstructionARM::EmulateTB (const uint32_t opcode, const ARMEncoding encod
bool success = false;
- uint32_t Rn; // the base register which contains the address of the table of branch lengths
- uint32_t Rm; // the index register which contains an integer pointing to a byte/halfword in the table
- bool is_tbh; // true if table branch halfword
- switch (encoding) {
- case eEncodingT1:
- Rn = Bits32(opcode, 19, 16);
- Rm = Bits32(opcode, 3, 0);
- is_tbh = BitIsSet(opcode, 4);
- if (Rn == 13 || BadReg(Rm))
- return false;
- if (InITBlock() && !LastInITBlock())
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rn; // the base register which contains the address of the table of branch lengths
+ uint32_t Rm; // the index register which contains an integer pointing to a byte/halfword in the table
+ bool is_tbh; // true if table branch halfword
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ is_tbh = BitIsSet(opcode, 4);
+ if (Rn == 13 || BadReg(Rm))
+ return false;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ default:
return false;
- break;
- default:
- return false;
- }
+ }
- // Read the address of the table from the operand register Rn.
- // The PC can be used, in which case the table immediately follows this instruction.
- uint32_t base = ReadCoreReg(Rm, &success);
- if (!success)
- return false;
+ // Read the address of the table from the operand register Rn.
+ // The PC can be used, in which case the table immediately follows this instruction.
+ uint32_t base = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
- // the table index
- uint32_t index = ReadCoreReg(Rm, &success);
- if (!success)
- return false;
+ // the table index
+ uint32_t index = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
- // the offsetted table address
- addr_t addr = base + (is_tbh ? index*2 : index);
+ // the offsetted table address
+ addr_t addr = base + (is_tbh ? index*2 : index);
- // PC-relative offset to branch forward
- EmulateInstruction::Context context;
- context.type = EmulateInstruction::eContextTableBranchReadMemory;
- uint32_t offset = MemURead(context, addr, is_tbh ? 2 : 1, 0, &success) * 2;
- if (!success)
- return false;
+ // PC-relative offset to branch forward
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextTableBranchReadMemory;
+ uint32_t offset = MemURead(context, addr, is_tbh ? 2 : 1, 0, &success) * 2;
+ if (!success)
+ return false;
- const uint32_t pc = ReadCoreReg(PC_REG, &success);
- if (!success)
- return false;
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
- // target address
- addr_t target = pc + offset;
- context.type = EmulateInstruction::eContextRelativeBranchImmediate;
- context.SetISAAndImmediateSigned (eModeThumb, 4 + offset);
+ // target address
+ addr_t target = pc + offset;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + offset);
- if (!BranchWritePC(context, target))
- return false;
+ if (!BranchWritePC(context, target))
+ return false;
+ }
return true;
}
@@ -2481,14 +2536,14 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
(result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
R[d] = result;
if setflags then
- APSR.N = result<31>;
- APSR.Z = IsZeroBit(result);
- APSR.C = carry;
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
APSR.V = overflow;
#endif
-
+
bool success = false;
-
+
if (ConditionPassed(opcode))
{
uint32_t d;
@@ -2496,8 +2551,8 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
bool setflags;
uint32_t imm32;
uint32_t carry_out;
-
- //EncodingSpecificOperations();
+
+ //EncodingSpecificOperations();
switch (encoding)
{
case eEncodingT1:
@@ -2506,7 +2561,7 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
n = Bits32 (opcode, 5, 3);
setflags = !InITBlock();
imm32 = Bits32 (opcode, 8,6);
-
+
break;
case eEncodingT2:
@@ -2515,28 +2570,30 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
n = Bits32 (opcode, 10, 8);
setflags = !InITBlock();
imm32 = Bits32 (opcode, 7, 0);
-
+
break;
-
+
case eEncodingT3:
// if Rd == '1111' && S == '1' then SEE CMN (immediate);
- // if Rn == '1101' then SEE ADD (SP plus immediate);
// d = UInt(Rd); n = UInt(Rn); setflags = (S == '1'); imm32 = ThumbExpandImm(i:imm3:imm8);
d = Bits32 (opcode, 11, 8);
n = Bits32 (opcode, 19, 16);
setflags = BitIsSet (opcode, 20);
imm32 = ThumbExpandImm_C (opcode, APSR_C, carry_out);
-
+
+ // if Rn == '1101' then SEE ADD (SP plus immediate);
+ if (n == 13)
+ return EmulateADDSPImm(opcode, eEncodingT3);
+
// if BadReg(d) || n == 15 then UNPREDICTABLE;
if (BadReg (d) || (n == 15))
return false;
-
+
break;
-
+
case eEncodingT4:
{
// if Rn == '1111' then SEE ADR;
- // if Rn == '1101' then SEE ADD (SP plus immediate);
// d = UInt(Rd); n = UInt(Rn); setflags = FALSE; imm32 = ZeroExtend(i:imm3:imm8, 32);
d = Bits32 (opcode, 11, 8);
n = Bits32 (opcode, 19, 16);
@@ -2545,31 +2602,36 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
uint32_t imm3 = Bits32 (opcode, 14, 12);
uint32_t imm8 = Bits32 (opcode, 7, 0);
imm32 = (i << 11) | (imm3 << 8) | imm8;
-
+
+ // if Rn == '1101' then SEE ADD (SP plus immediate);
+ if (n == 13)
+ return EmulateADDSPImm(opcode, eEncodingT4);
+
// if BadReg(d) then UNPREDICTABLE;
if (BadReg (d))
return false;
-
+
break;
- }
+ }
+
default:
return false;
}
-
+
uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
if (!success)
return false;
-
+
//(result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
AddWithCarryResult res = AddWithCarry (Rn, imm32, 0);
-
+
RegisterInfo reg_n;
GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, reg_n);
-
+
EmulateInstruction::Context context;
context.type = eContextArithmetic;
context.SetRegisterPlusOffset (reg_n, imm32);
-
+
//R[d] = result;
//if setflags then
//APSR.N = result<31>;
@@ -2578,7 +2640,7 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
//APSR.V = overflow;
if (!WriteCoreRegOptionalFlags (context, res.result, d, setflags, res.carry_out, res.overflow))
return false;
-
+
}
return true;
}
@@ -2631,7 +2693,13 @@ EmulateInstructionARM::EmulateADDImmARM (const uint32_t opcode, const ARMEncodin
AddWithCarryResult res = AddWithCarry(val1, imm32, 0);
EmulateInstruction::Context context;
- context.type = eContextArithmetic;
+ if (Rd == 13)
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ else if (Rd == GetFramePointerRegisterNumber())
+ context.type = EmulateInstruction::eContextSetFramePointer;
+ else
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+
RegisterInfo dwarf_reg;
GetRegisterInfo (eRegisterKindDWARF, Rn, dwarf_reg);
context.SetRegisterPlusOffset (dwarf_reg, imm32);
@@ -2947,6 +3015,13 @@ EmulateInstructionARM::EmulateCMPReg (const uint32_t opcode, const ARMEncoding e
if (Rn == 15 || Rm == 15)
return false;
break;
+ case eEncodingT3:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ if (Rn == 15 || BadReg(Rm))
+ return false;
+ break;
case eEncodingA1:
Rn = Bits32(opcode, 19, 16);
Rm = Bits32(opcode, 3, 0);
@@ -3995,8 +4070,22 @@ EmulateInstructionARM::EmulateLDRRtRnImm (const uint32_t opcode, const ARMEncodi
if (wback)
{
EmulateInstruction::Context ctx;
- ctx.type = EmulateInstruction::eContextAdjustBaseRegister;
- ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base));
+ if (Rn == 13)
+ {
+ ctx.type = eContextAdjustStackPointer;
+ ctx.SetImmediateSigned((int32_t) (offset_addr - base));
+ }
+ else if (Rn == GetFramePointerRegisterNumber())
+ {
+ ctx.type = eContextSetFramePointer;
+ ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base));
+ }
+ else
+ {
+ ctx.type = EmulateInstruction::eContextAdjustBaseRegister;
+ ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base));
+ }
+
if (!WriteRegisterUnsigned (ctx, eRegisterKindDWARF, dwarf_r0 + Rn, offset_addr))
return false;
@@ -6195,8 +6284,6 @@ EmulateInstructionARM::EmulateLDRBImmediate (const uint32_t opcode, const ARMEnc
break;
case eEncodingT2:
- // if Rt == '1111' then SEE PLD;
- // if Rn == '1111' then SEE LDRB (literal);
// t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
t = Bits32 (opcode, 15, 12);
n = Bits32 (opcode, 19, 16);
@@ -6206,7 +6293,15 @@ EmulateInstructionARM::EmulateLDRBImmediate (const uint32_t opcode, const ARMEnc
index = true;
add = true;
wback = false;
-
+
+ // if Rt == '1111' then SEE PLD;
+ if (t == 15)
+ return false; // PLD is not implemented yet
+
+ // if Rn == '1111' then SEE LDRB (literal);
+ if (n == 15)
+ return EmulateLDRBLiteral(opcode, eEncodingT1);
+
// if t == 13 then UNPREDICTABLE;
if (t == 13)
return false;
@@ -6214,14 +6309,12 @@ EmulateInstructionARM::EmulateLDRBImmediate (const uint32_t opcode, const ARMEnc
break;
case eEncodingT3:
- // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD;
- // if Rn == '1111' then SEE LDRB (literal);
// if P == '1' && U == '1' && W == '0' then SEE LDRBT;
// if P == '0' && W == '0' then UNDEFINED;
if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
return false;
- // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
t = Bits32 (opcode, 15, 12);
n = Bits32 (opcode, 19, 16);
imm32 = Bits32 (opcode, 7, 0);
@@ -6230,7 +6323,15 @@ EmulateInstructionARM::EmulateLDRBImmediate (const uint32_t opcode, const ARMEnc
index = BitIsSet (opcode, 10);
add = BitIsSet (opcode, 9);
wback = BitIsSet (opcode, 8);
-
+
+ // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD;
+ if (t == 15)
+ return false; // PLD is not implemented yet
+
+ // if Rn == '1111' then SEE LDRB (literal);
+ if (n == 15)
+ return EmulateLDRBLiteral(opcode, eEncodingT1);
+
// if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
if (BadReg (t) || (wback && (n == t)))
return false;
@@ -6312,11 +6413,14 @@ EmulateInstructionARM::EmulateLDRBLiteral (const uint32_t opcode, const ARMEncod
switch (encoding)
{
case eEncodingT1:
- // if Rt == '1111' then SEE PLD;
// t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
t = Bits32 (opcode, 15, 12);
imm32 = Bits32 (opcode, 11, 0);
add = BitIsSet (opcode, 23);
+
+ // if Rt == '1111' then SEE PLD;
+ if (t == 15)
+ return false; // PLD is not implemented yet
// if t == 13 then UNPREDICTABLE;
if (t == 13)
@@ -6417,8 +6521,6 @@ EmulateInstructionARM::EmulateLDRBRegister (const uint32_t opcode, const ARMEnco
break;
case eEncodingT2:
- // if Rt == '1111' then SEE PLD;
- // if Rn == '1111' then SEE LDRB (literal);
// t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
t = Bits32 (opcode, 15, 12);
n = Bits32 (opcode, 19, 16);
@@ -6432,6 +6534,14 @@ EmulateInstructionARM::EmulateLDRBRegister (const uint32_t opcode, const ARMEnco
// (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
shift_t = SRType_LSL;
shift_n = Bits32 (opcode, 5, 4);
+
+ // if Rt == '1111' then SEE PLD;
+ if (t == 15)
+ return false; // PLD is not implemented yet
+
+ // if Rn == '1111' then SEE LDRB (literal);
+ if (n == 15)
+ return EmulateLDRBLiteral(opcode, eEncodingT1);
// if t == 13 || BadReg(m) then UNPREDICTABLE;
if ((t == 13) || BadReg (m))
@@ -9154,46 +9264,55 @@ EmulateInstructionARM::EmulateSUBImmARM (const uint32_t opcode, const ARMEncodin
bool success = false;
- uint32_t Rd; // the destination register
- uint32_t Rn; // the first operand
- bool setflags;
- uint32_t imm32; // the immediate value to be subtracted from the value obtained from Rn
- switch (encoding) {
- case eEncodingA1:
- Rd = Bits32(opcode, 15, 12);
- Rn = Bits32(opcode, 19, 16);
- setflags = BitIsSet(opcode, 20);
- imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ bool setflags;
+ uint32_t imm32; // the immediate value to be subtracted from the value obtained from Rn
+ switch (encoding) {
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
- // if Rn == '1111' && S == '0' then SEE ADR;
- if (Rn == 15 && !setflags)
- return EmulateADR (opcode, eEncodingA2);
+ // if Rn == '1111' && S == '0' then SEE ADR;
+ if (Rn == 15 && !setflags)
+ return EmulateADR (opcode, eEncodingA2);
- // if Rn == '1101' then SEE SUB (SP minus immediate);
- if (Rn == 13)
- return EmulateSUBSPImm (opcode, eEncodingA1);
+ // if Rn == '1101' then SEE SUB (SP minus immediate);
+ if (Rn == 13)
+ return EmulateSUBSPImm (opcode, eEncodingA1);
- // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
- if (Rd == 15 && setflags)
- return EmulateSUBSPcLrEtc (opcode, encoding);
- break;
- default:
- return false;
- }
- // Read the register value from the operand register Rn.
- uint32_t reg_val = ReadCoreReg(Rn, &success);
- if (!success)
- return false;
-
- AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
- EmulateInstruction::Context context;
- context.type = EmulateInstruction::eContextImmediate;
- context.SetNoArgs ();
+ AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
- if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
- return false;
+ EmulateInstruction::Context context;
+ if (Rd == 13)
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ else
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, Rn, dwarf_reg);
+ int64_t imm32_signed = imm32;
+ context.SetRegisterPlusOffset (dwarf_reg, -imm32_signed);
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+ }
return true;
}
@@ -9696,14 +9815,20 @@ EmulateInstructionARM::EmulateSUBReg (const uint32_t opcode, const ARMEncoding e
break;
case eEncodingT2:
- // if Rd == Ô1111Õ && S == Ô1Õ then SEE CMP (register);
- // if Rn == Ô1101Õ then SEE SUB (SP minus register);
- // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == Ô1Õ);
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S =="1");
d = Bits32 (opcode, 11, 8);
n = Bits32 (opcode, 19, 16);
m = Bits32 (opcode, 3, 0);
setflags = BitIsSet (opcode, 20);
+
+ // if Rd == "1111" && S == "1" then SEE CMP (register);
+ if (d == 15 && setflags == 1)
+ return EmulateCMPImm (opcode, eEncodingT3);
+ // if Rn == "1101" then SEE SUB (SP minus register);
+ if (n == 13)
+ return EmulateSUBSPReg (opcode, eEncodingT1);
+
// (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2);
shift_n = DecodeImmShiftThumb (opcode, shift_t);
@@ -12338,9 +12463,9 @@ EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode, uint32
//----------------------------------------------------------------------
// Branch instructions
//----------------------------------------------------------------------
- { 0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b #imm24"},
- // To resolve ambiguity, "blx <label>" should come before "bl <label>".
+ // To resolve ambiguity, "blx <label>" should come before "b #imm24" and "bl <label>".
{ 0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
+ { 0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b #imm24"},
{ 0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
{ 0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
// for example, "bx lr"
@@ -12600,7 +12725,7 @@ EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode, uint
{ 0xf800d001, 0xf000c000, ARMV5_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
{ 0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
// for example, "bx lr"
- { 0xffffff87, 0x00004700, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"},
+ { 0xffffff87, 0x00004700, ARMvAll, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"},
// bxj
{ 0xfff0ffff, 0xf3c08f00, ARMV5J_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"},
// compare and branch
@@ -12710,6 +12835,7 @@ EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode, uint
{ 0xffffffc0, 0x00004280, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
// cmp (register) (Rn and Rm not both from r0-r7)
{ 0xffffff00, 0x00004500, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
+ { 0xfff08f00, 0xebb00f00, ARMvAll, eEncodingT3, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c>.w <Rn>, <Rm> {, <shift>}"},
// asr (immediate)
{ 0xfffff800, 0x00001000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateASRImm, "asrs|asr<c> <Rd>, <Rm>, #imm"},
{ 0xffef8030, 0xea4f0020, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRImm, "asr{s}<c>.w <Rd>, <Rm>, #imm"},
@@ -13025,8 +13151,7 @@ EmulateInstructionARM::ConditionPassed (const uint32_t opcode, bool *is_conditio
// opcodes different meanings, but always means execution happens.
if (is_conditional)
*is_conditional = false;
- result = true;
- break;
+ return true;
}
if (cond & 1)
@@ -13052,8 +13177,8 @@ EmulateInstructionARM::CurrentCond (const uint32_t opcode)
const uint32_t byte_size = m_opcode.GetByteSize();
if (byte_size == 2)
{
- if (Bits32(opcode, 15, 12) == 0x0d && Bits32(opcode, 11, 7) != 0x0f)
- return Bits32(opcode, 11, 7);
+ if (Bits32(opcode, 15, 12) == 0x0d && Bits32(opcode, 11, 8) != 0x0f)
+ return Bits32(opcode, 11, 8);
}
else if (byte_size == 4)
{
@@ -13643,16 +13768,12 @@ EmulateInstructionARM::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
UnwindPlan::RowSP row(new UnwindPlan::Row);
// Our previous Call Frame Address is the stack pointer
- row->SetCFARegister (dwarf_sp);
-
- // Our previous PC is in the LR
- row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, true);
- unwind_plan.AppendRow (row);
+ row->GetCFAValue().SetIsRegisterPlusOffset (dwarf_sp, 0);
- // All other registers are the same.
-
+ unwind_plan.AppendRow (row);
unwind_plan.SetSourceName ("EmulateInstructionARM");
unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
+ unwind_plan.SetReturnAddressRegister (dwarf_lr);
return true;
}
diff --git a/source/Plugins/Instruction/ARM/EmulationStateARM.cpp b/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
index bad4118971e0..6072264f1efc 100644
--- a/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
+++ b/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
@@ -233,7 +233,7 @@ EmulationStateARM::WritePseudoMemory (EmulateInstruction *instruction,
bool success;
EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
- uint64_t value = *((uint64_t *) dst);
+ uint64_t value = *((const uint64_t *) dst);
success = pseudo_state->StoreToPseudoAddress (addr, value, length);
if (success)
return length;
diff --git a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
index 3900af9b00d0..992df1fba59e 100644
--- a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
+++ b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
@@ -183,10 +183,10 @@ EmulateInstructionARM64::SetTargetTriple (const ArchSpec &arch)
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)
{
@@ -236,23 +236,53 @@ EmulateInstructionARM64::GetOpcodeForInstruction (const uint32_t opcode)
{ 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>]!" },
+
+ { 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, 0x29800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xa9800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x2d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <St>, <St2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x6d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xad800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
+
+ { 0xffc00000, 0x28800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xa8800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x2c800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "STP <St>, <St2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x6c800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xac800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
+
+ { 0xffc00000, 0x29400000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "LDP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0xa9400000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "LDP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0x2d400000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "LDP <St>, <St2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0x6d400000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "LDP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0xad400000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "LDP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]" },
+
+ { 0xffc00000, 0x29c00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xa9c00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x2dc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x6dc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xadc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
+
+ { 0xffc00000, 0x28c00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xa8c00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x2cc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x6cc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xacc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
+
+ { 0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateB, "B <label>" },
+ { 0xff000010, 0x54000000, No_VFP, &EmulateInstructionARM64::EmulateBcond, "B.<cond> <label>" },
+ { 0x7f000000, 0x34000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ, "CBZ <Wt>, <label>" },
+ { 0x7f000000, 0x35000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ, "CBNZ <Wt>, <label>" },
+ { 0x7f000000, 0x36000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ, "TBZ <R><t>, #<imm>, <label>" },
+ { 0x7f000000, 0x37000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ, "TBNZ <R><t>, #<imm>, <label>" },
};
static const size_t k_num_arm_opcodes = llvm::array_lengthof(g_opcodes);
@@ -262,10 +292,10 @@ EmulateInstructionARM64::GetOpcodeForInstruction (const uint32_t opcode)
if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)
return &g_opcodes[i];
}
- return NULL;
+ return nullptr;
}
-bool
+bool
EmulateInstructionARM64::ReadInstruction ()
{
bool success = false;
@@ -346,25 +376,139 @@ EmulateInstructionARM64::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
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);
+ row->GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, 0);
unwind_plan.AppendRow (row);
-
- // All other registers are the same.
-
unwind_plan.SetSourceName ("EmulateInstructionARM64");
unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
+ unwind_plan.SetReturnAddressRegister (arm64_dwarf::lr);
return true;
}
+uint32_t
+EmulateInstructionARM64::GetFramePointerRegisterNumber () const
+{
+ if (m_arch.GetTriple().getEnvironment() == llvm::Triple::Android)
+ return LLDB_INVALID_REGNUM; // Don't use frame pointer on android
+ return arm64_dwarf::sp;
+}
+
+bool
+EmulateInstructionARM64::UsingAArch32()
+{
+ bool aarch32 = m_opcode_pstate.RW == 1;
+ // if !HaveAnyAArch32() then assert !aarch32;
+ // if HighestELUsingAArch32() then assert aarch32;
+ return aarch32;
+}
+
+bool
+EmulateInstructionARM64::BranchTo (const Context &context, uint32_t N, addr_t target)
+{
+#if 0
+ // Set program counter to a new address, with a branch reason hint
+ // for possible use by hardware fetching the next instruction.
+ BranchTo(bits(N) target, BranchType branch_type)
+ Hint_Branch(branch_type);
+ if N == 32 then
+ assert UsingAArch32();
+ _PC = ZeroExtend(target);
+ else
+ assert N == 64 && !UsingAArch32();
+ // Remove the tag bits from a tagged target
+ case PSTATE.EL of
+ when EL0, EL1
+ if target<55> == '1' && TCR_EL1.TBI1 == '1' then
+ target<63:56> = '11111111';
+ if target<55> == '0' && TCR_EL1.TBI0 == '1' then
+ target<63:56> = '00000000';
+ when EL2
+ if TCR_EL2.TBI == '1' then
+ target<63:56> = '00000000';
+ when EL3
+ if TCR_EL3.TBI == '1' then
+ target<63:56> = '00000000';
+ _PC = target<63:0>;
+ return;
+#endif
+
+ addr_t addr;
+
+ //Hint_Branch(branch_type);
+ if (N == 32)
+ {
+ if (!UsingAArch32())
+ return false;
+ addr = target;
+ }
+ else if (N == 64)
+ {
+ if (UsingAArch32())
+ return false;
+ // TODO: Remove the tag bits from a tagged target
+ addr = target;
+ }
+ else
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, addr))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionARM64::ConditionHolds (const uint32_t cond, bool *is_conditional)
+{
+ // If we are ignoring conditions, then always return true.
+ // this allows us to iterate over disassembly code and still
+ // emulate an instruction even if we don't have all the right
+ // bits set in the CPSR register...
+ if (m_ignore_conditions)
+ return true;
+
+ if (is_conditional)
+ *is_conditional = true;
+
+ bool result = false;
+ switch (UnsignedBits(cond, 3, 1))
+ {
+ case 0:
+ result = (m_opcode_pstate.Z == 1);
+ break;
+ case 1:
+ result = (m_opcode_pstate.C == 1);
+ break;
+ case 2:
+ result = (m_opcode_pstate.N == 1);
+ break;
+ case 3:
+ result = (m_opcode_pstate.V == 1);
+ break;
+ case 4:
+ result = (m_opcode_pstate.C == 1 && m_opcode_pstate.Z == 0);
+ break;
+ case 5:
+ result = (m_opcode_pstate.N == m_opcode_pstate.V);
+ break;
+ case 6:
+ result = (m_opcode_pstate.N == m_opcode_pstate.V && m_opcode_pstate.Z == 0);
+ break;
+ case 7:
+ result = true;
+ if (is_conditional)
+ *is_conditional = false;
+ break;
+ }
+
+ if (cond & 1 && cond != 15)
+ result = !result;
+ return result;
+}
bool
EmulateInstructionARM64::Emulate_addsub_imm (const uint32_t opcode)
@@ -460,13 +604,13 @@ EmulateInstructionARM64::Emulate_addsub_imm (const uint32_t opcode)
if (arm64_dwarf::GetRegisterInfo (n, reg_info_Rn))
context.SetRegisterPlusOffset (reg_info_Rn, imm);
- if ((n == arm64_dwarf::sp || n == arm64_dwarf::fp) &&
+ if ((n == arm64_dwarf::sp || n == GetFramePointerRegisterNumber()) &&
d == arm64_dwarf::sp &&
!setflags)
{
context.type = EmulateInstruction::eContextAdjustStackPointer;
}
- else if (d == arm64_dwarf::fp &&
+ else if (d == GetFramePointerRegisterNumber() &&
n == arm64_dwarf::sp &&
!setflags)
{
@@ -476,8 +620,11 @@ EmulateInstructionARM64::Emulate_addsub_imm (const uint32_t opcode)
{
context.type = EmulateInstruction::eContextImmediate;
}
- WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::x0 + d, result);
-
+
+ // If setflags && d == arm64_dwarf::sp then d = WZR/XZR. See CMN, CMP
+ if (!setflags || d != arm64_dwarf::sp)
+ WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::x0 + d, result);
+
return false;
}
@@ -487,7 +634,6 @@ EmulateInstructionARM64::Emulate_ldstpair_off (const uint32_t opcode)
return Emulate_ldstpair (opcode, AddrMode_OFF);
}
-
bool
EmulateInstructionARM64::Emulate_ldstpair_pre (const uint32_t opcode)
{
@@ -495,6 +641,12 @@ EmulateInstructionARM64::Emulate_ldstpair_pre (const uint32_t opcode)
}
bool
+EmulateInstructionARM64::Emulate_ldstpair_post (const uint32_t opcode)
+{
+ return Emulate_ldstpair (opcode, AddrMode_POST);
+}
+
+bool
EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mode)
{
uint32_t opc = Bits32(opcode, 31, 30);
@@ -623,26 +775,24 @@ EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mod
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.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 (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is based off of the sp or fp register
+ {
+ context_t.type = eContextPushRegisterOnStack;
+ context_t2.type = eContextPushRegisterOnStack;
+ }
+
if (!ReadRegister (&reg_info_Rt, data_Rt))
return false;
@@ -665,6 +815,12 @@ EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mod
case MemOp_LOAD:
{
+ if (n == 31 || n == GetFramePointerRegisterNumber()) // if this load is based off of the sp or fp register
+ {
+ context_t.type = eContextPopRegisterOffStack;
+ context_t2.type = eContextPopRegisterOffStack;
+ }
+
if (rt_unknown)
memset (buffer, 'U', reg_info_Rt.byte_size);
else
@@ -717,3 +873,152 @@ EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mod
}
return true;
}
+
+bool
+EmulateInstructionARM64::EmulateB (const uint32_t opcode)
+{
+#if 0
+ // ARM64 pseudo code...
+ if branch_type == BranchType_CALL then X[30] = PC[] + 4;
+ BranchTo(PC[] + offset, branch_type);
+#endif
+
+ bool success = false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
+ if (!success)
+ return false;
+
+ int64_t offset = llvm::SignExtend64<28>(Bits32(opcode, 25, 0) << 2);
+ BranchType branch_type = Bit32(opcode, 31) ? BranchType_CALL : BranchType_JMP;
+ addr_t target = pc + offset;
+ context.SetImmediateSigned(offset);
+
+ switch (branch_type)
+ {
+ case BranchType_CALL:
+ {
+ addr_t x30 = pc + 4;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::x30, x30))
+ return false;
+ }
+ break;
+ case BranchType_JMP:
+ break;
+ default:
+ return false;
+ }
+
+ if (!BranchTo(context, 64, target))
+ return false;
+ return true;
+}
+
+bool
+EmulateInstructionARM64::EmulateBcond (const uint32_t opcode)
+{
+#if 0
+ // ARM64 pseudo code...
+ bits(64) offset = SignExtend(imm19:'00', 64);
+ bits(4) condition = cond;
+ if ConditionHolds(condition) then
+ BranchTo(PC[] + offset, BranchType_JMP);
+#endif
+
+ if (ConditionHolds(Bits32(opcode, 3, 0)))
+ {
+ bool success = false;
+
+ const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
+ if (!success)
+ return false;
+
+ int64_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
+ addr_t target = pc + offset;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ context.SetImmediateSigned(offset);
+ if (!BranchTo(context, 64, target))
+ return false;
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM64::EmulateCBZ (const uint32_t opcode)
+{
+#if 0
+ integer t = UInt(Rt);
+ integer datasize = if sf == '1' then 64 else 32;
+ boolean iszero = (op == '0');
+ bits(64) offset = SignExtend(imm19:'00', 64);
+
+ bits(datasize) operand1 = X[t];
+ if IsZero(operand1) == iszero then
+ BranchTo(PC[] + offset, BranchType_JMP);
+#endif
+
+ bool success = false;
+
+ uint32_t t = Bits32(opcode, 4, 0);
+ bool is_zero = Bit32(opcode, 24) == 0;
+ int32_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
+
+ const uint64_t operand = ReadRegisterUnsigned(eRegisterKindDWARF, arm64_dwarf::x0 + t, 0, &success);
+ if (!success)
+ return false;
+
+ if (m_ignore_conditions || ((operand == 0) == is_zero))
+ {
+ const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ context.SetImmediateSigned(offset);
+ if (!BranchTo(context, 64, pc + offset))
+ return false;
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM64::EmulateTBZ (const uint32_t opcode)
+{
+#if 0
+ integer t = UInt(Rt);
+ integer datasize = if b5 == '1' then 64 else 32;
+ integer bit_pos = UInt(b5:b40);
+ bit bit_val = op;
+ bits(64) offset = SignExtend(imm14:'00', 64);
+#endif
+
+ bool success = false;
+
+ uint32_t t = Bits32(opcode, 4, 0);
+ uint32_t bit_pos = (Bit32(opcode, 31) << 6) | (Bits32(opcode, 23, 19));
+ uint32_t bit_val = Bit32(opcode, 24);
+ int64_t offset = llvm::SignExtend64<16>(Bits32(opcode, 18, 5) << 2);
+
+ const uint64_t operand = ReadRegisterUnsigned(eRegisterKindDWARF, arm64_dwarf::x0 + t, 0, &success);
+ if (!success)
+ return false;
+
+ if (m_ignore_conditions || Bit32(operand, bit_pos) == bit_val)
+ {
+ const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ context.SetImmediateSigned(offset);
+ if (!BranchTo(context, 64, pc + offset))
+ return false;
+ }
+ return true;
+}
diff --git a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h
index 7e18d09a0ee2..b74eddeaaf63 100644
--- a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h
+++ b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h
@@ -265,30 +265,45 @@ protected:
static Opcode*
GetOpcodeForInstruction (const uint32_t opcode);
+ uint32_t
+ GetFramePointerRegisterNumber() const;
+
+ bool
+ BranchTo (const Context &context, uint32_t N, lldb::addr_t target);
+
+ bool
+ ConditionHolds (const uint32_t cond, bool *is_conditional = nullptr);
+
+ bool
+ UsingAArch32 ();
+
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_post (const uint32_t opcode);
+
bool
Emulate_ldstpair (const uint32_t opcode, AddrMode a_mode);
+ bool
+ EmulateB (const uint32_t opcode);
+
+ bool
+ EmulateBcond (const uint32_t opcode);
+
+ bool
+ EmulateCBZ (const uint32_t opcode);
+
+ bool
+ EmulateTBZ (const uint32_t opcode);
+
ProcState m_opcode_pstate;
ProcState m_emulated_pstate; // This can get updated by the opcode.
bool m_ignore_conditions;
diff --git a/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
new file mode 100644
index 000000000000..1af25dc817c5
--- /dev/null
+++ b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
@@ -0,0 +1,2918 @@
+//===-- EmulateInstructionMIPS.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EmulateInstructionMIPS.h"
+
+#include <stdlib.h>
+
+#include "llvm-c/Disassembler.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCDisassembler.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Opcode.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/UnwindPlan.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+#include "Plugins/Process/Utility/RegisterContext_mips64.h" //mips32 has same registers nos as mips64
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define UInt(x) ((uint64_t)x)
+#define integer int64_t
+
+
+//----------------------------------------------------------------------
+//
+// EmulateInstructionMIPS implementation
+//
+//----------------------------------------------------------------------
+
+#ifdef __mips__
+extern "C" {
+ void LLVMInitializeMipsTargetInfo ();
+ void LLVMInitializeMipsTarget ();
+ void LLVMInitializeMipsAsmPrinter ();
+ void LLVMInitializeMipsTargetMC ();
+ void LLVMInitializeMipsDisassembler ();
+}
+#endif
+
+EmulateInstructionMIPS::EmulateInstructionMIPS (const lldb_private::ArchSpec &arch) :
+ EmulateInstruction (arch)
+{
+ /* Create instance of llvm::MCDisassembler */
+ std::string Error;
+ llvm::Triple triple = arch.GetTriple();
+ const llvm::Target *target = llvm::TargetRegistry::lookupTarget (triple.getTriple(), Error);
+
+ /*
+ * If we fail to get the target then we haven't registered it. The SystemInitializerCommon
+ * does not initialize targets, MCs and disassemblers. However we need the MCDisassembler
+ * to decode the instructions so that the decoding complexity stays with LLVM.
+ * Initialize the MIPS targets and disassemblers.
+ */
+#ifdef __mips__
+ if (!target)
+ {
+ LLVMInitializeMipsTargetInfo ();
+ LLVMInitializeMipsTarget ();
+ LLVMInitializeMipsAsmPrinter ();
+ LLVMInitializeMipsTargetMC ();
+ LLVMInitializeMipsDisassembler ();
+ target = llvm::TargetRegistry::lookupTarget (triple.getTriple(), Error);
+ }
+#endif
+
+ assert (target);
+
+ llvm::StringRef cpu;
+
+ switch (arch.GetCore())
+ {
+ case ArchSpec::eCore_mips32:
+ case ArchSpec::eCore_mips32el:
+ cpu = "mips32"; break;
+ case ArchSpec::eCore_mips32r2:
+ case ArchSpec::eCore_mips32r2el:
+ cpu = "mips32r2"; break;
+ case ArchSpec::eCore_mips32r3:
+ case ArchSpec::eCore_mips32r3el:
+ cpu = "mips32r3"; break;
+ case ArchSpec::eCore_mips32r5:
+ case ArchSpec::eCore_mips32r5el:
+ cpu = "mips32r5"; break;
+ case ArchSpec::eCore_mips32r6:
+ case ArchSpec::eCore_mips32r6el:
+ cpu = "mips32r6"; break;
+ case ArchSpec::eCore_mips64:
+ case ArchSpec::eCore_mips64el:
+ cpu = "mips64"; break;
+ case ArchSpec::eCore_mips64r2:
+ case ArchSpec::eCore_mips64r2el:
+ cpu = "mips64r2"; break;
+ case ArchSpec::eCore_mips64r3:
+ case ArchSpec::eCore_mips64r3el:
+ cpu = "mips64r3"; break;
+ case ArchSpec::eCore_mips64r5:
+ case ArchSpec::eCore_mips64r5el:
+ cpu = "mips64r5"; break;
+ case ArchSpec::eCore_mips64r6:
+ case ArchSpec::eCore_mips64r6el:
+ cpu = "mips64r6"; break;
+ default:
+ cpu = "generic"; break;
+ }
+
+ m_reg_info.reset (target->createMCRegInfo (triple.getTriple()));
+ assert (m_reg_info.get());
+
+ m_insn_info.reset (target->createMCInstrInfo());
+ assert (m_insn_info.get());
+
+ m_asm_info.reset (target->createMCAsmInfo (*m_reg_info, triple.getTriple()));
+ m_subtype_info.reset (target->createMCSubtargetInfo (triple.getTriple(), cpu, ""));
+ assert (m_asm_info.get() && m_subtype_info.get());
+
+ m_context.reset (new llvm::MCContext (m_asm_info.get(), m_reg_info.get(), nullptr));
+ assert (m_context.get());
+
+ m_disasm.reset (target->createMCDisassembler (*m_subtype_info, *m_context));
+ assert (m_disasm.get());
+}
+
+void
+EmulateInstructionMIPS::Initialize ()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic (),
+ GetPluginDescriptionStatic (),
+ CreateInstance);
+}
+
+void
+EmulateInstructionMIPS::Terminate ()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+ConstString
+EmulateInstructionMIPS::GetPluginNameStatic ()
+{
+ ConstString g_plugin_name ("lldb.emulate-instruction.mips32");
+ return g_plugin_name;
+}
+
+lldb_private::ConstString
+EmulateInstructionMIPS::GetPluginName()
+{
+ static ConstString g_plugin_name ("EmulateInstructionMIPS");
+ return g_plugin_name;
+}
+
+const char *
+EmulateInstructionMIPS::GetPluginDescriptionStatic ()
+{
+ return "Emulate instructions for the MIPS32 architecture.";
+}
+
+EmulateInstruction *
+EmulateInstructionMIPS::CreateInstance (const ArchSpec &arch, InstructionType inst_type)
+{
+ if (EmulateInstructionMIPS::SupportsEmulatingInstructionsOfTypeStatic(inst_type))
+ {
+ if (arch.GetTriple().getArch() == llvm::Triple::mips
+ || arch.GetTriple().getArch() == llvm::Triple::mipsel)
+ {
+ std::auto_ptr<EmulateInstructionMIPS> emulate_insn_ap (new EmulateInstructionMIPS (arch));
+ if (emulate_insn_ap.get())
+ return emulate_insn_ap.release();
+ }
+ }
+
+ return NULL;
+}
+
+bool
+EmulateInstructionMIPS::SetTargetTriple (const ArchSpec &arch)
+{
+ if (arch.GetTriple().getArch () == llvm::Triple::mips
+ || arch.GetTriple().getArch () == llvm::Triple::mipsel)
+ return true;
+ return false;
+}
+
+const char *
+EmulateInstructionMIPS::GetRegisterName (unsigned reg_num, bool alternate_name)
+{
+ if (alternate_name)
+ {
+ switch (reg_num)
+ {
+ case gcc_dwarf_sp_mips: return "r29";
+ case gcc_dwarf_r30_mips: return "r30";
+ case gcc_dwarf_ra_mips: return "r31";
+ case gcc_dwarf_f0_mips: return "f0";
+ case gcc_dwarf_f1_mips: return "f1";
+ case gcc_dwarf_f2_mips: return "f2";
+ case gcc_dwarf_f3_mips: return "f3";
+ case gcc_dwarf_f4_mips: return "f4";
+ case gcc_dwarf_f5_mips: return "f5";
+ case gcc_dwarf_f6_mips: return "f6";
+ case gcc_dwarf_f7_mips: return "f7";
+ case gcc_dwarf_f8_mips: return "f8";
+ case gcc_dwarf_f9_mips: return "f9";
+ case gcc_dwarf_f10_mips: return "f10";
+ case gcc_dwarf_f11_mips: return "f11";
+ case gcc_dwarf_f12_mips: return "f12";
+ case gcc_dwarf_f13_mips: return "f13";
+ case gcc_dwarf_f14_mips: return "f14";
+ case gcc_dwarf_f15_mips: return "f15";
+ case gcc_dwarf_f16_mips: return "f16";
+ case gcc_dwarf_f17_mips: return "f17";
+ case gcc_dwarf_f18_mips: return "f18";
+ case gcc_dwarf_f19_mips: return "f19";
+ case gcc_dwarf_f20_mips: return "f20";
+ case gcc_dwarf_f21_mips: return "f21";
+ case gcc_dwarf_f22_mips: return "f22";
+ case gcc_dwarf_f23_mips: return "f23";
+ case gcc_dwarf_f24_mips: return "f24";
+ case gcc_dwarf_f25_mips: return "f25";
+ case gcc_dwarf_f26_mips: return "f26";
+ case gcc_dwarf_f27_mips: return "f27";
+ case gcc_dwarf_f28_mips: return "f28";
+ case gcc_dwarf_f29_mips: return "f29";
+ case gcc_dwarf_f30_mips: return "f30";
+ case gcc_dwarf_f31_mips: return "f31";
+ default:
+ break;
+ }
+ return nullptr;
+ }
+
+ switch (reg_num)
+ {
+ case gcc_dwarf_zero_mips: return "r0";
+ case gcc_dwarf_r1_mips: return "r1";
+ case gcc_dwarf_r2_mips: return "r2";
+ case gcc_dwarf_r3_mips: return "r3";
+ case gcc_dwarf_r4_mips: return "r4";
+ case gcc_dwarf_r5_mips: return "r5";
+ case gcc_dwarf_r6_mips: return "r6";
+ case gcc_dwarf_r7_mips: return "r7";
+ case gcc_dwarf_r8_mips: return "r8";
+ case gcc_dwarf_r9_mips: return "r9";
+ case gcc_dwarf_r10_mips: return "r10";
+ case gcc_dwarf_r11_mips: return "r11";
+ case gcc_dwarf_r12_mips: return "r12";
+ case gcc_dwarf_r13_mips: return "r13";
+ case gcc_dwarf_r14_mips: return "r14";
+ case gcc_dwarf_r15_mips: return "r15";
+ case gcc_dwarf_r16_mips: return "r16";
+ case gcc_dwarf_r17_mips: return "r17";
+ case gcc_dwarf_r18_mips: return "r18";
+ case gcc_dwarf_r19_mips: return "r19";
+ case gcc_dwarf_r20_mips: return "r20";
+ case gcc_dwarf_r21_mips: return "r21";
+ case gcc_dwarf_r22_mips: return "r22";
+ case gcc_dwarf_r23_mips: return "r23";
+ case gcc_dwarf_r24_mips: return "r24";
+ case gcc_dwarf_r25_mips: return "r25";
+ case gcc_dwarf_r26_mips: return "r26";
+ case gcc_dwarf_r27_mips: return "r27";
+ case gcc_dwarf_gp_mips: return "gp";
+ case gcc_dwarf_sp_mips: return "sp";
+ case gcc_dwarf_r30_mips: return "fp";
+ case gcc_dwarf_ra_mips: return "ra";
+ case gcc_dwarf_sr_mips: return "sr";
+ case gcc_dwarf_lo_mips: return "lo";
+ case gcc_dwarf_hi_mips: return "hi";
+ case gcc_dwarf_bad_mips: return "bad";
+ case gcc_dwarf_cause_mips: return "cause";
+ case gcc_dwarf_pc_mips: return "pc";
+ case gcc_dwarf_f0_mips: return "fp_reg[0]";
+ case gcc_dwarf_f1_mips: return "fp_reg[1]";
+ case gcc_dwarf_f2_mips: return "fp_reg[2]";
+ case gcc_dwarf_f3_mips: return "fp_reg[3]";
+ case gcc_dwarf_f4_mips: return "fp_reg[4]";
+ case gcc_dwarf_f5_mips: return "fp_reg[5]";
+ case gcc_dwarf_f6_mips: return "fp_reg[6]";
+ case gcc_dwarf_f7_mips: return "fp_reg[7]";
+ case gcc_dwarf_f8_mips: return "fp_reg[8]";
+ case gcc_dwarf_f9_mips: return "fp_reg[9]";
+ case gcc_dwarf_f10_mips: return "fp_reg[10]";
+ case gcc_dwarf_f11_mips: return "fp_reg[11]";
+ case gcc_dwarf_f12_mips: return "fp_reg[12]";
+ case gcc_dwarf_f13_mips: return "fp_reg[13]";
+ case gcc_dwarf_f14_mips: return "fp_reg[14]";
+ case gcc_dwarf_f15_mips: return "fp_reg[15]";
+ case gcc_dwarf_f16_mips: return "fp_reg[16]";
+ case gcc_dwarf_f17_mips: return "fp_reg[17]";
+ case gcc_dwarf_f18_mips: return "fp_reg[18]";
+ case gcc_dwarf_f19_mips: return "fp_reg[19]";
+ case gcc_dwarf_f20_mips: return "fp_reg[20]";
+ case gcc_dwarf_f21_mips: return "fp_reg[21]";
+ case gcc_dwarf_f22_mips: return "fp_reg[22]";
+ case gcc_dwarf_f23_mips: return "fp_reg[23]";
+ case gcc_dwarf_f24_mips: return "fp_reg[24]";
+ case gcc_dwarf_f25_mips: return "fp_reg[25]";
+ case gcc_dwarf_f26_mips: return "fp_reg[26]";
+ case gcc_dwarf_f27_mips: return "fp_reg[27]";
+ case gcc_dwarf_f28_mips: return "fp_reg[28]";
+ case gcc_dwarf_f29_mips: return "fp_reg[29]";
+ case gcc_dwarf_f30_mips: return "fp_reg[30]";
+ case gcc_dwarf_f31_mips: return "fp_reg[31]";
+ case gcc_dwarf_fcsr_mips: return "fcsr";
+ case gcc_dwarf_fir_mips: return "fir";
+ }
+ return nullptr;
+}
+
+bool
+EmulateInstructionMIPS::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 = gcc_dwarf_pc_mips; break;
+ case LLDB_REGNUM_GENERIC_SP: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_sp_mips; break;
+ case LLDB_REGNUM_GENERIC_FP: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_r30_mips; break;
+ case LLDB_REGNUM_GENERIC_RA: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_ra_mips; break;
+ case LLDB_REGNUM_GENERIC_FLAGS: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_sr_mips; break;
+ default:
+ return false;
+ }
+ }
+
+ if (reg_kind == eRegisterKindDWARF)
+ {
+ ::memset (&reg_info, 0, sizeof(RegisterInfo));
+ ::memset (reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
+
+ if (reg_num == gcc_dwarf_sr_mips || reg_num == gcc_dwarf_fcsr_mips || reg_num == gcc_dwarf_fir_mips)
+ {
+ reg_info.byte_size = 4;
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ }
+ else if ((int)reg_num >= gcc_dwarf_zero_mips && (int)reg_num <= gcc_dwarf_f31_mips)
+ {
+ reg_info.byte_size = 4;
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ }
+ else
+ {
+ return false;
+ }
+
+ reg_info.name = GetRegisterName (reg_num, false);
+ reg_info.alt_name = GetRegisterName (reg_num, true);
+ reg_info.kinds[eRegisterKindDWARF] = reg_num;
+
+ switch (reg_num)
+ {
+ case gcc_dwarf_r30_mips: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; break;
+ case gcc_dwarf_ra_mips: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; break;
+ case gcc_dwarf_sp_mips: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; break;
+ case gcc_dwarf_pc_mips: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; break;
+ case gcc_dwarf_sr_mips: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; break;
+ default: break;
+ }
+ return true;
+ }
+ return false;
+}
+
+EmulateInstructionMIPS::MipsOpcode*
+EmulateInstructionMIPS::GetOpcodeForInstruction (const char *op_name)
+{
+ static EmulateInstructionMIPS::MipsOpcode
+ g_opcodes[] =
+ {
+ //----------------------------------------------------------------------
+ // Prologue/Epilogue instructions
+ //----------------------------------------------------------------------
+ { "ADDiu", &EmulateInstructionMIPS::Emulate_ADDiu, "ADDIU rt,rs,immediate" },
+ { "SW", &EmulateInstructionMIPS::Emulate_SW, "SW rt,offset(rs)" },
+ { "LW", &EmulateInstructionMIPS::Emulate_LW, "LW rt,offset(base)" },
+
+ //----------------------------------------------------------------------
+ // Branch instructions
+ //----------------------------------------------------------------------
+ { "BEQ", &EmulateInstructionMIPS::Emulate_BEQ, "BEQ rs,rt,offset" },
+ { "BNE", &EmulateInstructionMIPS::Emulate_BNE, "BNE rs,rt,offset" },
+ { "BEQL", &EmulateInstructionMIPS::Emulate_BEQL, "BEQL rs,rt,offset" },
+ { "BNEL", &EmulateInstructionMIPS::Emulate_BNEL, "BNEL rs,rt,offset" },
+ { "BGEZALL", &EmulateInstructionMIPS::Emulate_BGEZALL, "BGEZALL rt,offset" },
+ { "BAL", &EmulateInstructionMIPS::Emulate_BAL, "BAL offset" },
+ { "BGEZAL", &EmulateInstructionMIPS::Emulate_BGEZAL, "BGEZAL rs,offset" },
+ { "BALC", &EmulateInstructionMIPS::Emulate_BALC, "BALC offset" },
+ { "BC", &EmulateInstructionMIPS::Emulate_BC, "BC offset" },
+ { "BGEZ", &EmulateInstructionMIPS::Emulate_BGEZ, "BGEZ rs,offset" },
+ { "BLEZALC", &EmulateInstructionMIPS::Emulate_BLEZALC, "BLEZALC rs,offset" },
+ { "BGEZALC", &EmulateInstructionMIPS::Emulate_BGEZALC, "BGEZALC rs,offset" },
+ { "BLTZALC", &EmulateInstructionMIPS::Emulate_BLTZALC, "BLTZALC rs,offset" },
+ { "BGTZALC", &EmulateInstructionMIPS::Emulate_BGTZALC, "BGTZALC rs,offset" },
+ { "BEQZALC", &EmulateInstructionMIPS::Emulate_BEQZALC, "BEQZALC rs,offset" },
+ { "BNEZALC", &EmulateInstructionMIPS::Emulate_BNEZALC, "BNEZALC rs,offset" },
+ { "BEQC", &EmulateInstructionMIPS::Emulate_BEQC, "BEQC rs,rt,offset" },
+ { "BNEC", &EmulateInstructionMIPS::Emulate_BNEC, "BNEC rs,rt,offset" },
+ { "BLTC", &EmulateInstructionMIPS::Emulate_BLTC, "BLTC rs,rt,offset" },
+ { "BGEC", &EmulateInstructionMIPS::Emulate_BGEC, "BGEC rs,rt,offset" },
+ { "BLTUC", &EmulateInstructionMIPS::Emulate_BLTUC, "BLTUC rs,rt,offset" },
+ { "BGEUC", &EmulateInstructionMIPS::Emulate_BGEUC, "BGEUC rs,rt,offset" },
+ { "BLTZC", &EmulateInstructionMIPS::Emulate_BLTZC, "BLTZC rt,offset" },
+ { "BLEZC", &EmulateInstructionMIPS::Emulate_BLEZC, "BLEZC rt,offset" },
+ { "BGEZC", &EmulateInstructionMIPS::Emulate_BGEZC, "BGEZC rt,offset" },
+ { "BGTZC", &EmulateInstructionMIPS::Emulate_BGTZC, "BGTZC rt,offset" },
+ { "BEQZC", &EmulateInstructionMIPS::Emulate_BEQZC, "BEQZC rt,offset" },
+ { "BNEZC", &EmulateInstructionMIPS::Emulate_BNEZC, "BNEZC rt,offset" },
+ { "BGEZL", &EmulateInstructionMIPS::Emulate_BGEZL, "BGEZL rt,offset" },
+ { "BGTZ", &EmulateInstructionMIPS::Emulate_BGTZ, "BGTZ rt,offset" },
+ { "BGTZL", &EmulateInstructionMIPS::Emulate_BGTZL, "BGTZL rt,offset" },
+ { "BLEZ", &EmulateInstructionMIPS::Emulate_BLEZ, "BLEZ rt,offset" },
+ { "BLEZL", &EmulateInstructionMIPS::Emulate_BLEZL, "BLEZL rt,offset" },
+ { "BLTZ", &EmulateInstructionMIPS::Emulate_BLTZ, "BLTZ rt,offset" },
+ { "BLTZAL", &EmulateInstructionMIPS::Emulate_BLTZAL, "BLTZAL rt,offset" },
+ { "BLTZALL", &EmulateInstructionMIPS::Emulate_BLTZALL, "BLTZALL rt,offset" },
+ { "BLTZL", &EmulateInstructionMIPS::Emulate_BLTZL, "BLTZL rt,offset" },
+ { "BOVC", &EmulateInstructionMIPS::Emulate_BOVC, "BOVC rs,rt,offset" },
+ { "BNVC", &EmulateInstructionMIPS::Emulate_BNVC, "BNVC rs,rt,offset" },
+ { "J", &EmulateInstructionMIPS::Emulate_J, "J target" },
+ { "JAL", &EmulateInstructionMIPS::Emulate_JAL, "JAL target" },
+ { "JALX", &EmulateInstructionMIPS::Emulate_JAL, "JALX target" },
+ { "JALR", &EmulateInstructionMIPS::Emulate_JALR, "JALR target" },
+ { "JALR_HB", &EmulateInstructionMIPS::Emulate_JALR, "JALR.HB target" },
+ { "JIALC", &EmulateInstructionMIPS::Emulate_JIALC, "JIALC rt,offset" },
+ { "JIC", &EmulateInstructionMIPS::Emulate_JIC, "JIC rt,offset" },
+ { "JR", &EmulateInstructionMIPS::Emulate_JR, "JR target" },
+ { "JR_HB", &EmulateInstructionMIPS::Emulate_JR, "JR.HB target" },
+ { "BC1F", &EmulateInstructionMIPS::Emulate_BC1F, "BC1F cc, offset" },
+ { "BC1T", &EmulateInstructionMIPS::Emulate_BC1T, "BC1T cc, offset" },
+ { "BC1FL", &EmulateInstructionMIPS::Emulate_BC1FL, "BC1FL cc, offset" },
+ { "BC1TL", &EmulateInstructionMIPS::Emulate_BC1TL, "BC1TL cc, offset" },
+ { "BC1EQZ", &EmulateInstructionMIPS::Emulate_BC1EQZ, "BC1EQZ ft, offset" },
+ { "BC1NEZ", &EmulateInstructionMIPS::Emulate_BC1NEZ, "BC1NEZ ft, offset" },
+ { "BC1ANY2F", &EmulateInstructionMIPS::Emulate_BC1ANY2F, "BC1ANY2F cc, offset" },
+ { "BC1ANY2T", &EmulateInstructionMIPS::Emulate_BC1ANY2T, "BC1ANY2T cc, offset" },
+ { "BC1ANY4F", &EmulateInstructionMIPS::Emulate_BC1ANY4F, "BC1ANY4F cc, offset" },
+ { "BC1ANY4T", &EmulateInstructionMIPS::Emulate_BC1ANY4T, "BC1ANY4T cc, offset" },
+ };
+
+ static const size_t k_num_mips_opcodes = llvm::array_lengthof(g_opcodes);
+
+ for (size_t i = 0; i < k_num_mips_opcodes; ++i)
+ {
+ if (! strcasecmp (g_opcodes[i].op_name, op_name))
+ return &g_opcodes[i];
+ }
+
+ return NULL;
+}
+
+bool
+EmulateInstructionMIPS::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
+EmulateInstructionMIPS::EvaluateInstruction (uint32_t evaluate_options)
+{
+ bool success = false;
+ llvm::MCInst mc_insn;
+ uint64_t insn_size;
+ DataExtractor data;
+
+ /* Keep the complexity of the decode logic with the llvm::MCDisassembler class. */
+ if (m_opcode.GetData (data))
+ {
+ llvm::MCDisassembler::DecodeStatus decode_status;
+ llvm::ArrayRef<uint8_t> raw_insn (data.GetDataStart(), data.GetByteSize());
+ decode_status = m_disasm->getInstruction (mc_insn, insn_size, raw_insn, m_addr, llvm::nulls(), llvm::nulls());
+ if (decode_status != llvm::MCDisassembler::Success)
+ return false;
+ }
+
+ /*
+ * mc_insn.getOpcode() returns decoded opcode. However to make use
+ * of llvm::Mips::<insn> we would need "MipsGenInstrInfo.inc".
+ */
+ const char *op_name = m_insn_info->getName (mc_insn.getOpcode ());
+
+ if (op_name == NULL)
+ return false;
+
+ /*
+ * Decoding has been done already. Just get the call-back function
+ * and emulate the instruction.
+ */
+ MipsOpcode *opcode_data = GetOpcodeForInstruction (op_name);
+
+ if (opcode_data == NULL)
+ return false;
+
+ uint64_t old_pc = 0, new_pc = 0;
+ const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
+
+ if (auto_advance_pc)
+ {
+ old_pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+ }
+
+ /* emulate instruction */
+ success = (this->*opcode_data->callback) (mc_insn);
+ if (!success)
+ return false;
+
+ if (auto_advance_pc)
+ {
+ new_pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ /* If we haven't changed the PC, change it here */
+ if (old_pc == new_pc)
+ {
+ new_pc += 4;
+ Context context;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, new_pc))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::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->GetCFAValue().SetIsRegisterPlusOffset(gcc_dwarf_sp_mips, 0);
+
+ // Our previous PC is in the RA
+ row->SetRegisterLocationToRegister(gcc_dwarf_pc_mips, gcc_dwarf_ra_mips, can_replace);
+
+ unwind_plan.AppendRow (row);
+
+ // All other registers are the same.
+ unwind_plan.SetSourceName ("EmulateInstructionMIPS");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::nonvolatile_reg_p (uint32_t regnum)
+{
+ switch (regnum)
+ {
+ case gcc_dwarf_r16_mips:
+ case gcc_dwarf_r17_mips:
+ case gcc_dwarf_r18_mips:
+ case gcc_dwarf_r19_mips:
+ case gcc_dwarf_r20_mips:
+ case gcc_dwarf_r21_mips:
+ case gcc_dwarf_r22_mips:
+ case gcc_dwarf_r23_mips:
+ case gcc_dwarf_gp_mips:
+ case gcc_dwarf_sp_mips:
+ case gcc_dwarf_r30_mips:
+ case gcc_dwarf_ra_mips:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_ADDiu (llvm::MCInst& insn)
+{
+ bool success = false;
+ const uint32_t imm16 = insn.getOperand(2).getImm();
+ uint32_t imm = SignedBits(imm16, 15, 0);
+ uint64_t result;
+ uint32_t src, dst;
+
+ dst = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ src = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+
+ /* Check if this is addiu sp,<src>,imm16 */
+ if (dst == gcc_dwarf_sp_mips)
+ {
+ /* read <src> register */
+ uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + src, 0, &success);
+ if (!success)
+ return false;
+
+ result = src_opd_val + imm;
+
+ Context context;
+ RegisterInfo reg_info_sp;
+ if (GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_sp_mips, reg_info_sp))
+ context.SetRegisterPlusOffset (reg_info_sp, imm);
+
+ /* We are allocating bytes on stack */
+ context.type = eContextAdjustStackPointer;
+
+ WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_sp_mips, result);
+ }
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_SW (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t imm16 = insn.getOperand(2).getImm();
+ uint32_t imm = SignedBits(imm16, 15, 0);
+ uint32_t src, base;
+
+ src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+
+ /* We look for sp based non-volatile register stores */
+ if (base == gcc_dwarf_sp_mips && nonvolatile_reg_p (src))
+ {
+ uint32_t address;
+ RegisterInfo reg_info_base;
+ RegisterInfo reg_info_src;
+
+ if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips + base, reg_info_base)
+ || !GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips + src, reg_info_src))
+ return false;
+
+ /* read SP */
+ address = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + base, 0, &success);
+ if (!success)
+ return false;
+
+ /* destination address */
+ address = address + imm;
+
+ Context context;
+ RegisterValue data_src;
+ context.type = eContextPushRegisterOnStack;
+ context.SetRegisterToRegisterPlusOffset (reg_info_src, reg_info_base, 0);
+
+ uint8_t buffer [RegisterValue::kMaxRegisterByteSize];
+ Error error;
+
+ if (!ReadRegister (&reg_info_base, data_src))
+ return false;
+
+ if (data_src.GetAsMemoryData (&reg_info_src, buffer, reg_info_src.byte_size, eByteOrderLittle, error) == 0)
+ return false;
+
+ if (!WriteMemory (context, address, buffer, reg_info_src.byte_size))
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_LW (llvm::MCInst& insn)
+{
+ uint32_t src, base;
+
+ src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+
+ if (base == gcc_dwarf_sp_mips && nonvolatile_reg_p (src))
+ {
+ RegisterValue data_src;
+ RegisterInfo reg_info_src;
+
+ if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips + src, reg_info_src))
+ return false;
+
+ Context context;
+ context.type = eContextRegisterLoad;
+
+ if (!WriteRegister (context, &reg_info_src, data_src))
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BEQ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BEQ rs, rt, offset
+ * condition <- (GPR[rs] = GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val == rt_val)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BNE (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BNE rs, rt, offset
+ * condition <- (GPR[rs] != GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val != rt_val)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BEQL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BEQL rs, rt, offset
+ * condition <- (GPR[rs] = GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val == rt_val)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BNEL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BNEL rs, rt, offset
+ * condition <- (GPR[rs] != GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val != rt_val)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGEZL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BGEZL rs, offset
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BLTZL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BLTZL rs, offset
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGTZL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BGTZL rs, offset
+ * condition <- (GPR[rs] > 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val > 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BLEZL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BLEZL rs, offset
+ * condition <- (GPR[rs] <= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val <= 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGTZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BGTZ rs, offset
+ * condition <- (GPR[rs] > 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val > 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BLEZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BLEZ rs, offset
+ * condition <- (GPR[rs] <= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val <= 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BLTZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BLTZ rs, offset
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGEZALL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BGEZALL rt, offset
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BAL (llvm::MCInst& insn)
+{
+ bool success = false;
+ int32_t offset, pc, target;
+
+ /*
+ * BAL offset
+ * offset = sign_ext (offset << 2)
+ * RA = PC + 8
+ * PC = PC + offset
+ */
+ offset = insn.getOperand(0).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ target = pc + offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ int32_t offset, pc, target;
+
+ /*
+ * BALC offset
+ * offset = sign_ext (offset << 2)
+ * RA = PC + 4
+ * PC = PC + 4 + offset
+ */
+ offset = insn.getOperand(0).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ target = pc + 4 + offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGEZAL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BGEZAL rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * RA = PC + 8
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if ((int32_t) rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BLTZAL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BLTZAL rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * RA = PC + 8
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if ((int32_t) rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BLTZALL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BLTZALL rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * RA = PC + 8
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 8))
+ return false;
+
+ return true;
+}
+
+
+bool
+EmulateInstructionMIPS::Emulate_BLEZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BLEZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] <= 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val <= 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGEZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BGEZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BLTZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BLTZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGTZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BGTZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] > 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val > 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BEQZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target, rs_val;
+
+ /*
+ * BEQZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] == 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val == 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BNEZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target, rs_val;
+
+ /*
+ * BNEZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] != 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val != 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGEZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target, rs_val;
+
+ /*
+ * BGEZ rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BC (llvm::MCInst& insn)
+{
+ bool success = false;
+ int32_t offset, pc, target;
+
+ /*
+ * BC offset
+ * offset = sign_ext (offset << 2)
+ * PC = PC + 4 + offset
+ */
+ offset = insn.getOperand(0).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ target = pc + 4 + offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BEQC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BEQC rs, rt, offset
+ * condition <- (GPR[rs] = GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val == rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BNEC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BNEC rs, rt, offset
+ * condition <- (GPR[rs] != GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val != rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BLTC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target;
+ int32_t rs_val, rt_val;
+
+ /*
+ * BLTC rs, rt, offset
+ * condition <- (GPR[rs] < GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val < rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGEC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target;
+ int32_t rs_val, rt_val;
+
+ /*
+ * BGEC rs, rt, offset
+ * condition <- (GPR[rs] > GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val > rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BLTUC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target;
+ uint32_t rs_val, rt_val;
+
+ /*
+ * BLTUC rs, rt, offset
+ * condition <- (GPR[rs] < GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val < rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGEUC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target;
+ uint32_t rs_val, rt_val;
+
+ /*
+ * BGEUC rs, rt, offset
+ * condition <- (GPR[rs] > GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val > rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BLTZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BLTZC rs, offset
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val < 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BLEZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BLEZC rs, offset
+ * condition <- (GPR[rs] <= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val <= 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGEZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BGEZC rs, offset
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val >= 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BGTZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ int32_t rs_val;
+
+ /*
+ * BGTZC rs, offset
+ * condition <- (GPR[rs] > 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val > 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BEQZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ uint32_t rs_val;
+
+ /*
+ * BEQZC rs, offset
+ * condition <- (GPR[rs] = 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val == 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BNEZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target;
+ uint32_t rs_val;
+
+ /*
+ * BNEZC rs, offset
+ * condition <- (GPR[rs] != 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val != 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+static int
+IsAdd64bitOverflow (int32_t a, int32_t b)
+{
+ int32_t r = (uint32_t) a + (uint32_t) b;
+ return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0);
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BOVC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target;
+ int32_t rs_val, rt_val;
+
+ /*
+ * BOVC rs, rt, offset
+ * condition <- overflow(GPR[rs] + GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (IsAdd64bitOverflow (rs_val, rt_val))
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BNVC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target;
+ int32_t rs_val, rt_val;
+
+ /*
+ * BNVC rs, rt, offset
+ * condition <- overflow(GPR[rs] + GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (! IsAdd64bitOverflow (rs_val, rt_val))
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_J (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t offset, pc;
+
+ /*
+ * J offset
+ * offset = sign_ext (offset << 2)
+ * PC = PC[63-28] | offset
+ */
+ offset = insn.getOperand(0).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ /* This is a PC-region branch and not PC-relative */
+ pc = (pc & 0xF0000000UL) | offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, pc))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_JAL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t offset, target, pc;
+
+ /*
+ * JAL offset
+ * offset = sign_ext (offset << 2)
+ * PC = PC[63-28] | offset
+ */
+ offset = insn.getOperand(0).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ /* This is a PC-region branch and not PC-relative */
+ target = (pc & 0xF0000000UL) | offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_JALR (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ uint32_t pc, rs_val;
+
+ /*
+ * JALR rt, rs
+ * GPR[rt] = PC + 8
+ * PC = GPR[rs]
+ */
+ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rs = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, rs_val))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_JIALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rt;
+ int32_t target, offset, pc, rt_val;
+
+ /*
+ * JIALC rt, offset
+ * offset = sign_ext (offset)
+ * PC = GPR[rt] + offset
+ * RA = PC + 4
+ */
+ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ target = rt_val + offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_JIC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rt;
+ int32_t target, offset, rt_val;
+
+ /*
+ * JIC rt, offset
+ * offset = sign_ext (offset)
+ * PC = GPR[rt] + offset
+ */
+ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ target = rt_val + offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_JR (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ uint32_t rs_val;
+
+ /*
+ * JR rs
+ * PC = GPR[rs]
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, rs_val))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BC1F (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int32_t target, pc, offset;
+
+ /*
+ * BC1F cc, offset
+ * condition <- (FPConditionCode(cc) == 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ if ((fcsr & (1 << cc)) == 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BC1T (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int32_t target, pc, offset;
+
+ /*
+ * BC1T cc, offset
+ * condition <- (FPConditionCode(cc) != 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ if ((fcsr & (1 << cc)) != 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BC1FL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int32_t target, pc, offset;
+
+ /*
+ * BC1F cc, offset
+ * condition <- (FPConditionCode(cc) == 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ if ((fcsr & (1 << cc)) == 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BC1TL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int32_t target, pc, offset;
+
+ /*
+ * BC1T cc, offset
+ * condition <- (FPConditionCode(cc) != 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ if ((fcsr & (1 << cc)) != 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BC1EQZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t ft;
+ uint32_t ft_val;
+ int32_t target, pc, offset;
+
+ /*
+ * BC1EQZ ft, offset
+ * condition <- (FPR[ft].bit0 == 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + 4 + offset
+ */
+ ft = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ ft_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + ft, 0, &success);
+ if (!success)
+ return false;
+
+ if ((ft_val & 1) == 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BC1NEZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t ft;
+ uint32_t ft_val;
+ int32_t target, pc, offset;
+
+ /*
+ * BC1NEZ ft, offset
+ * condition <- (FPR[ft].bit0 != 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + 4 + offset
+ */
+ ft = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ ft_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips + ft, 0, &success);
+ if (!success)
+ return false;
+
+ if ((ft_val & 1) != 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BC1ANY2F (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int32_t target, pc, offset;
+
+ /*
+ * BC1ANY2F cc, offset
+ * condition <- (FPConditionCode(cc) == 0
+ * || FPConditionCode(cc+1) == 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ /* if any one bit is 0 */
+ if (((fcsr >> cc) & 3) != 3)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BC1ANY2T (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int32_t target, pc, offset;
+
+ /*
+ * BC1ANY2T cc, offset
+ * condition <- (FPConditionCode(cc) == 1
+ * || FPConditionCode(cc+1) == 1)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ /* if any one bit is 1 */
+ if (((fcsr >> cc) & 3) != 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BC1ANY4F (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int32_t target, pc, offset;
+
+ /*
+ * BC1ANY4F cc, offset
+ * condition <- (FPConditionCode(cc) == 0
+ * || FPConditionCode(cc+1) == 0)
+ * || FPConditionCode(cc+2) == 0)
+ * || FPConditionCode(cc+3) == 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ /* if any one bit is 0 */
+ if (((fcsr >> cc) & 0xf) != 0xf)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS::Emulate_BC1ANY4T (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int32_t target, pc, offset;
+
+ /*
+ * BC1ANY4T cc, offset
+ * condition <- (FPConditionCode(cc) == 1
+ * || FPConditionCode(cc+1) == 1)
+ * || FPConditionCode(cc+2) == 1)
+ * || FPConditionCode(cc+3) == 1)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ /* if any one bit is 1 */
+ if (((fcsr >> cc) & 0xf) != 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
diff --git a/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
new file mode 100644
index 000000000000..25d8fc8891d5
--- /dev/null
+++ b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
@@ -0,0 +1,313 @@
+//===-- EmulateInstructionMIPS.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef EmulateInstructionMIPS_h_
+#define EmulateInstructionMIPS_h_
+
+namespace llvm
+{
+ class MCDisassembler;
+ class MCSubtargetInfo;
+ class MCRegisterInfo;
+ class MCAsmInfo;
+ class MCContext;
+ class MCInstrInfo;
+ class MCInst;
+}
+
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+class EmulateInstructionMIPS : 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:
+ case lldb_private::eInstructionTypePCModifying:
+ return true;
+
+ 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);
+
+ EmulateInstructionMIPS (const lldb_private::ArchSpec &arch);
+
+ 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);
+
+
+protected:
+
+ typedef struct
+ {
+ const char *op_name;
+ bool (EmulateInstructionMIPS::*callback) (llvm::MCInst& insn);
+ const char *insn_name;
+ } MipsOpcode;
+
+ static MipsOpcode*
+ GetOpcodeForInstruction (const char *op_name);
+
+ bool
+ Emulate_ADDiu (llvm::MCInst& insn);
+
+ bool
+ Emulate_SW (llvm::MCInst& insn);
+
+ bool
+ Emulate_LW (llvm::MCInst& insn);
+
+ bool
+ Emulate_BEQ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNE (llvm::MCInst& insn);
+
+ bool
+ Emulate_BEQL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNEL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZALL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BAL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZAL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLEZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGTZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BEQZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNEZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BEQC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNEC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTUC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEUC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLEZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGTZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BEQZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNEZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGTZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGTZL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLEZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLEZL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZAL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZALL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BOVC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNVC (llvm::MCInst& insn);
+
+ bool
+ Emulate_J (llvm::MCInst& insn);
+
+ bool
+ Emulate_JAL (llvm::MCInst& insn);
+
+ bool
+ Emulate_JALR (llvm::MCInst& insn);
+
+ bool
+ Emulate_JIALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_JIC (llvm::MCInst& insn);
+
+ bool
+ Emulate_JR (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1F (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1T (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1FL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1TL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1EQZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1NEZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1ANY2F (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1ANY2T (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1ANY4F (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1ANY4T (llvm::MCInst& insn);
+
+ bool
+ nonvolatile_reg_p (uint32_t regnum);
+
+ const char *
+ GetRegisterName (unsigned reg_num, bool altnernate_name);
+
+private:
+ std::unique_ptr<llvm::MCDisassembler> m_disasm;
+ std::unique_ptr<llvm::MCSubtargetInfo> m_subtype_info;
+ std::unique_ptr<llvm::MCRegisterInfo> m_reg_info;
+ std::unique_ptr<llvm::MCAsmInfo> m_asm_info;
+ std::unique_ptr<llvm::MCContext> m_context;
+ std::unique_ptr<llvm::MCInstrInfo> m_insn_info;
+};
+
+#endif // EmulateInstructionMIPS_h_
diff --git a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
new file mode 100644
index 000000000000..7abf687342c1
--- /dev/null
+++ b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
@@ -0,0 +1,2920 @@
+//===-- EmulateInstructionMIPS64.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EmulateInstructionMIPS64.h"
+
+#include <stdlib.h>
+
+#include "llvm-c/Disassembler.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCDisassembler.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Opcode.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/UnwindPlan.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+#include "Plugins/Process/Utility/RegisterContext_mips64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define UInt(x) ((uint64_t)x)
+#define integer int64_t
+
+
+//----------------------------------------------------------------------
+//
+// EmulateInstructionMIPS64 implementation
+//
+//----------------------------------------------------------------------
+
+#ifdef __mips__
+extern "C" {
+ void LLVMInitializeMipsTargetInfo ();
+ void LLVMInitializeMipsTarget ();
+ void LLVMInitializeMipsAsmPrinter ();
+ void LLVMInitializeMipsTargetMC ();
+ void LLVMInitializeMipsDisassembler ();
+}
+#endif
+
+EmulateInstructionMIPS64::EmulateInstructionMIPS64 (const lldb_private::ArchSpec &arch) :
+ EmulateInstruction (arch)
+{
+ /* Create instance of llvm::MCDisassembler */
+ std::string Error;
+ llvm::Triple triple = arch.GetTriple();
+ const llvm::Target *target = llvm::TargetRegistry::lookupTarget (triple.getTriple(), Error);
+
+ /*
+ * If we fail to get the target then we haven't registered it. The SystemInitializerCommon
+ * does not initialize targets, MCs and disassemblers. However we need the MCDisassembler
+ * to decode the instructions so that the decoding complexity stays with LLVM.
+ * Initialize the MIPS targets and disassemblers.
+ */
+#ifdef __mips__
+ if (!target)
+ {
+ LLVMInitializeMipsTargetInfo ();
+ LLVMInitializeMipsTarget ();
+ LLVMInitializeMipsAsmPrinter ();
+ LLVMInitializeMipsTargetMC ();
+ LLVMInitializeMipsDisassembler ();
+ target = llvm::TargetRegistry::lookupTarget (triple.getTriple(), Error);
+ }
+#endif
+
+ assert (target);
+
+ llvm::StringRef cpu;
+
+ switch (arch.GetCore())
+ {
+ case ArchSpec::eCore_mips32:
+ case ArchSpec::eCore_mips32el:
+ cpu = "mips32"; break;
+ case ArchSpec::eCore_mips32r2:
+ case ArchSpec::eCore_mips32r2el:
+ cpu = "mips32r2"; break;
+ case ArchSpec::eCore_mips32r3:
+ case ArchSpec::eCore_mips32r3el:
+ cpu = "mips32r3"; break;
+ case ArchSpec::eCore_mips32r5:
+ case ArchSpec::eCore_mips32r5el:
+ cpu = "mips32r5"; break;
+ case ArchSpec::eCore_mips32r6:
+ case ArchSpec::eCore_mips32r6el:
+ cpu = "mips32r6"; break;
+ case ArchSpec::eCore_mips64:
+ case ArchSpec::eCore_mips64el:
+ cpu = "mips64"; break;
+ case ArchSpec::eCore_mips64r2:
+ case ArchSpec::eCore_mips64r2el:
+ cpu = "mips64r2"; break;
+ case ArchSpec::eCore_mips64r3:
+ case ArchSpec::eCore_mips64r3el:
+ cpu = "mips64r3"; break;
+ case ArchSpec::eCore_mips64r5:
+ case ArchSpec::eCore_mips64r5el:
+ cpu = "mips64r5"; break;
+ case ArchSpec::eCore_mips64r6:
+ case ArchSpec::eCore_mips64r6el:
+ cpu = "mips64r6"; break;
+ default:
+ cpu = "generic"; break;
+ }
+
+ m_reg_info.reset (target->createMCRegInfo (triple.getTriple()));
+ assert (m_reg_info.get());
+
+ m_insn_info.reset (target->createMCInstrInfo());
+ assert (m_insn_info.get());
+
+ m_asm_info.reset (target->createMCAsmInfo (*m_reg_info, triple.getTriple()));
+ m_subtype_info.reset (target->createMCSubtargetInfo (triple.getTriple(), cpu, ""));
+ assert (m_asm_info.get() && m_subtype_info.get());
+
+ m_context.reset (new llvm::MCContext (m_asm_info.get(), m_reg_info.get(), nullptr));
+ assert (m_context.get());
+
+ m_disasm.reset (target->createMCDisassembler (*m_subtype_info, *m_context));
+ assert (m_disasm.get());
+}
+
+void
+EmulateInstructionMIPS64::Initialize ()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic (),
+ GetPluginDescriptionStatic (),
+ CreateInstance);
+}
+
+void
+EmulateInstructionMIPS64::Terminate ()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+ConstString
+EmulateInstructionMIPS64::GetPluginNameStatic ()
+{
+ ConstString g_plugin_name ("lldb.emulate-instruction.mips64");
+ return g_plugin_name;
+}
+
+lldb_private::ConstString
+EmulateInstructionMIPS64::GetPluginName()
+{
+ static ConstString g_plugin_name ("EmulateInstructionMIPS64");
+ return g_plugin_name;
+}
+
+const char *
+EmulateInstructionMIPS64::GetPluginDescriptionStatic ()
+{
+ return "Emulate instructions for the MIPS64 architecture.";
+}
+
+EmulateInstruction *
+EmulateInstructionMIPS64::CreateInstance (const ArchSpec &arch, InstructionType inst_type)
+{
+ if (EmulateInstructionMIPS64::SupportsEmulatingInstructionsOfTypeStatic(inst_type))
+ {
+ if (arch.GetTriple().getArch() == llvm::Triple::mips64
+ || arch.GetTriple().getArch() == llvm::Triple::mips64el)
+ {
+ std::auto_ptr<EmulateInstructionMIPS64> emulate_insn_ap (new EmulateInstructionMIPS64 (arch));
+ if (emulate_insn_ap.get())
+ return emulate_insn_ap.release();
+ }
+ }
+
+ return NULL;
+}
+
+bool
+EmulateInstructionMIPS64::SetTargetTriple (const ArchSpec &arch)
+{
+ if (arch.GetTriple().getArch () == llvm::Triple::mips64
+ || arch.GetTriple().getArch () == llvm::Triple::mips64el)
+ return true;
+ return false;
+}
+
+const char *
+EmulateInstructionMIPS64::GetRegisterName (unsigned reg_num, bool alternate_name)
+{
+ if (alternate_name)
+ {
+ switch (reg_num)
+ {
+ case gcc_dwarf_sp_mips64: return "r29";
+ case gcc_dwarf_r30_mips64: return "r30";
+ case gcc_dwarf_ra_mips64: return "r31";
+ case gcc_dwarf_f0_mips64: return "f0";
+ case gcc_dwarf_f1_mips64: return "f1";
+ case gcc_dwarf_f2_mips64: return "f2";
+ case gcc_dwarf_f3_mips64: return "f3";
+ case gcc_dwarf_f4_mips64: return "f4";
+ case gcc_dwarf_f5_mips64: return "f5";
+ case gcc_dwarf_f6_mips64: return "f6";
+ case gcc_dwarf_f7_mips64: return "f7";
+ case gcc_dwarf_f8_mips64: return "f8";
+ case gcc_dwarf_f9_mips64: return "f9";
+ case gcc_dwarf_f10_mips64: return "f10";
+ case gcc_dwarf_f11_mips64: return "f11";
+ case gcc_dwarf_f12_mips64: return "f12";
+ case gcc_dwarf_f13_mips64: return "f13";
+ case gcc_dwarf_f14_mips64: return "f14";
+ case gcc_dwarf_f15_mips64: return "f15";
+ case gcc_dwarf_f16_mips64: return "f16";
+ case gcc_dwarf_f17_mips64: return "f17";
+ case gcc_dwarf_f18_mips64: return "f18";
+ case gcc_dwarf_f19_mips64: return "f19";
+ case gcc_dwarf_f20_mips64: return "f20";
+ case gcc_dwarf_f21_mips64: return "f21";
+ case gcc_dwarf_f22_mips64: return "f22";
+ case gcc_dwarf_f23_mips64: return "f23";
+ case gcc_dwarf_f24_mips64: return "f24";
+ case gcc_dwarf_f25_mips64: return "f25";
+ case gcc_dwarf_f26_mips64: return "f26";
+ case gcc_dwarf_f27_mips64: return "f27";
+ case gcc_dwarf_f28_mips64: return "f28";
+ case gcc_dwarf_f29_mips64: return "f29";
+ case gcc_dwarf_f30_mips64: return "f30";
+ case gcc_dwarf_f31_mips64: return "f31";
+ default:
+ break;
+ }
+ return nullptr;
+ }
+
+ switch (reg_num)
+ {
+ case gcc_dwarf_zero_mips64: return "r0";
+ case gcc_dwarf_r1_mips64: return "r1";
+ case gcc_dwarf_r2_mips64: return "r2";
+ case gcc_dwarf_r3_mips64: return "r3";
+ case gcc_dwarf_r4_mips64: return "r4";
+ case gcc_dwarf_r5_mips64: return "r5";
+ case gcc_dwarf_r6_mips64: return "r6";
+ case gcc_dwarf_r7_mips64: return "r7";
+ case gcc_dwarf_r8_mips64: return "r8";
+ case gcc_dwarf_r9_mips64: return "r9";
+ case gcc_dwarf_r10_mips64: return "r10";
+ case gcc_dwarf_r11_mips64: return "r11";
+ case gcc_dwarf_r12_mips64: return "r12";
+ case gcc_dwarf_r13_mips64: return "r13";
+ case gcc_dwarf_r14_mips64: return "r14";
+ case gcc_dwarf_r15_mips64: return "r15";
+ case gcc_dwarf_r16_mips64: return "r16";
+ case gcc_dwarf_r17_mips64: return "r17";
+ case gcc_dwarf_r18_mips64: return "r18";
+ case gcc_dwarf_r19_mips64: return "r19";
+ case gcc_dwarf_r20_mips64: return "r20";
+ case gcc_dwarf_r21_mips64: return "r21";
+ case gcc_dwarf_r22_mips64: return "r22";
+ case gcc_dwarf_r23_mips64: return "r23";
+ case gcc_dwarf_r24_mips64: return "r24";
+ case gcc_dwarf_r25_mips64: return "r25";
+ case gcc_dwarf_r26_mips64: return "r26";
+ case gcc_dwarf_r27_mips64: return "r27";
+ case gcc_dwarf_gp_mips64: return "gp";
+ case gcc_dwarf_sp_mips64: return "sp";
+ case gcc_dwarf_r30_mips64: return "fp";
+ case gcc_dwarf_ra_mips64: return "ra";
+ case gcc_dwarf_sr_mips64: return "sr";
+ case gcc_dwarf_lo_mips64: return "lo";
+ case gcc_dwarf_hi_mips64: return "hi";
+ case gcc_dwarf_bad_mips64: return "bad";
+ case gcc_dwarf_cause_mips64: return "cause";
+ case gcc_dwarf_pc_mips64: return "pc";
+ case gcc_dwarf_f0_mips64: return "fp_reg[0]";
+ case gcc_dwarf_f1_mips64: return "fp_reg[1]";
+ case gcc_dwarf_f2_mips64: return "fp_reg[2]";
+ case gcc_dwarf_f3_mips64: return "fp_reg[3]";
+ case gcc_dwarf_f4_mips64: return "fp_reg[4]";
+ case gcc_dwarf_f5_mips64: return "fp_reg[5]";
+ case gcc_dwarf_f6_mips64: return "fp_reg[6]";
+ case gcc_dwarf_f7_mips64: return "fp_reg[7]";
+ case gcc_dwarf_f8_mips64: return "fp_reg[8]";
+ case gcc_dwarf_f9_mips64: return "fp_reg[9]";
+ case gcc_dwarf_f10_mips64: return "fp_reg[10]";
+ case gcc_dwarf_f11_mips64: return "fp_reg[11]";
+ case gcc_dwarf_f12_mips64: return "fp_reg[12]";
+ case gcc_dwarf_f13_mips64: return "fp_reg[13]";
+ case gcc_dwarf_f14_mips64: return "fp_reg[14]";
+ case gcc_dwarf_f15_mips64: return "fp_reg[15]";
+ case gcc_dwarf_f16_mips64: return "fp_reg[16]";
+ case gcc_dwarf_f17_mips64: return "fp_reg[17]";
+ case gcc_dwarf_f18_mips64: return "fp_reg[18]";
+ case gcc_dwarf_f19_mips64: return "fp_reg[19]";
+ case gcc_dwarf_f20_mips64: return "fp_reg[20]";
+ case gcc_dwarf_f21_mips64: return "fp_reg[21]";
+ case gcc_dwarf_f22_mips64: return "fp_reg[22]";
+ case gcc_dwarf_f23_mips64: return "fp_reg[23]";
+ case gcc_dwarf_f24_mips64: return "fp_reg[24]";
+ case gcc_dwarf_f25_mips64: return "fp_reg[25]";
+ case gcc_dwarf_f26_mips64: return "fp_reg[26]";
+ case gcc_dwarf_f27_mips64: return "fp_reg[27]";
+ case gcc_dwarf_f28_mips64: return "fp_reg[28]";
+ case gcc_dwarf_f29_mips64: return "fp_reg[29]";
+ case gcc_dwarf_f30_mips64: return "fp_reg[30]";
+ case gcc_dwarf_f31_mips64: return "fp_reg[31]";
+ case gcc_dwarf_fcsr_mips64: return "fcsr";
+ case gcc_dwarf_fir_mips64: return "fir";
+ }
+ return nullptr;
+}
+
+bool
+EmulateInstructionMIPS64::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 = gcc_dwarf_pc_mips64; break;
+ case LLDB_REGNUM_GENERIC_SP: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_sp_mips64; break;
+ case LLDB_REGNUM_GENERIC_FP: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_r30_mips64; break;
+ case LLDB_REGNUM_GENERIC_RA: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_ra_mips64; break;
+ case LLDB_REGNUM_GENERIC_FLAGS: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_sr_mips64; break;
+ default:
+ return false;
+ }
+ }
+
+ if (reg_kind == eRegisterKindDWARF)
+ {
+ ::memset (&reg_info, 0, sizeof(RegisterInfo));
+ ::memset (reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
+
+ if (reg_num == gcc_dwarf_sr_mips64 || reg_num == gcc_dwarf_fcsr_mips64 || reg_num == gcc_dwarf_fir_mips64)
+ {
+ reg_info.byte_size = 4;
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ }
+ else if ((int)reg_num >= gcc_dwarf_zero_mips64 && (int)reg_num <= gcc_dwarf_f31_mips64)
+ {
+ reg_info.byte_size = 8;
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ }
+ else
+ {
+ return false;
+ }
+
+ reg_info.name = GetRegisterName (reg_num, false);
+ reg_info.alt_name = GetRegisterName (reg_num, true);
+ reg_info.kinds[eRegisterKindDWARF] = reg_num;
+
+ switch (reg_num)
+ {
+ case gcc_dwarf_r30_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; break;
+ case gcc_dwarf_ra_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; break;
+ case gcc_dwarf_sp_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; break;
+ case gcc_dwarf_pc_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; break;
+ case gcc_dwarf_sr_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; break;
+ default: break;
+ }
+ return true;
+ }
+ return false;
+}
+
+EmulateInstructionMIPS64::MipsOpcode*
+EmulateInstructionMIPS64::GetOpcodeForInstruction (const char *op_name)
+{
+ static EmulateInstructionMIPS64::MipsOpcode
+ g_opcodes[] =
+ {
+ //----------------------------------------------------------------------
+ // Prologue/Epilogue instructions
+ //----------------------------------------------------------------------
+ { "DADDiu", &EmulateInstructionMIPS64::Emulate_DADDiu, "DADDIU rt,rs,immediate" },
+ { "SD", &EmulateInstructionMIPS64::Emulate_SD, "SD rt,offset(rs)" },
+ { "LD", &EmulateInstructionMIPS64::Emulate_LD, "LD rt,offset(base)" },
+
+ //----------------------------------------------------------------------
+ // Branch instructions
+ //----------------------------------------------------------------------
+ { "BEQ", &EmulateInstructionMIPS64::Emulate_BEQ, "BEQ rs,rt,offset" },
+ { "BNE", &EmulateInstructionMIPS64::Emulate_BNE, "BNE rs,rt,offset" },
+ { "BEQL", &EmulateInstructionMIPS64::Emulate_BEQL, "BEQL rs,rt,offset" },
+ { "BNEL", &EmulateInstructionMIPS64::Emulate_BNEL, "BNEL rs,rt,offset" },
+ { "BGEZALL", &EmulateInstructionMIPS64::Emulate_BGEZALL, "BGEZALL rt,offset" },
+ { "BAL", &EmulateInstructionMIPS64::Emulate_BAL, "BAL offset" },
+ { "BGEZAL", &EmulateInstructionMIPS64::Emulate_BGEZAL, "BGEZAL rs,offset" },
+ { "BALC", &EmulateInstructionMIPS64::Emulate_BALC, "BALC offset" },
+ { "BC", &EmulateInstructionMIPS64::Emulate_BC, "BC offset" },
+ { "BGEZ", &EmulateInstructionMIPS64::Emulate_BGEZ, "BGEZ rs,offset" },
+ { "BLEZALC", &EmulateInstructionMIPS64::Emulate_BLEZALC, "BLEZALC rs,offset" },
+ { "BGEZALC", &EmulateInstructionMIPS64::Emulate_BGEZALC, "BGEZALC rs,offset" },
+ { "BLTZALC", &EmulateInstructionMIPS64::Emulate_BLTZALC, "BLTZALC rs,offset" },
+ { "BGTZALC", &EmulateInstructionMIPS64::Emulate_BGTZALC, "BGTZALC rs,offset" },
+ { "BEQZALC", &EmulateInstructionMIPS64::Emulate_BEQZALC, "BEQZALC rs,offset" },
+ { "BNEZALC", &EmulateInstructionMIPS64::Emulate_BNEZALC, "BNEZALC rs,offset" },
+ { "BEQC", &EmulateInstructionMIPS64::Emulate_BEQC, "BEQC rs,rt,offset" },
+ { "BNEC", &EmulateInstructionMIPS64::Emulate_BNEC, "BNEC rs,rt,offset" },
+ { "BLTC", &EmulateInstructionMIPS64::Emulate_BLTC, "BLTC rs,rt,offset" },
+ { "BGEC", &EmulateInstructionMIPS64::Emulate_BGEC, "BGEC rs,rt,offset" },
+ { "BLTUC", &EmulateInstructionMIPS64::Emulate_BLTUC, "BLTUC rs,rt,offset" },
+ { "BGEUC", &EmulateInstructionMIPS64::Emulate_BGEUC, "BGEUC rs,rt,offset" },
+ { "BLTZC", &EmulateInstructionMIPS64::Emulate_BLTZC, "BLTZC rt,offset" },
+ { "BLEZC", &EmulateInstructionMIPS64::Emulate_BLEZC, "BLEZC rt,offset" },
+ { "BGEZC", &EmulateInstructionMIPS64::Emulate_BGEZC, "BGEZC rt,offset" },
+ { "BGTZC", &EmulateInstructionMIPS64::Emulate_BGTZC, "BGTZC rt,offset" },
+ { "BEQZC", &EmulateInstructionMIPS64::Emulate_BEQZC, "BEQZC rt,offset" },
+ { "BNEZC", &EmulateInstructionMIPS64::Emulate_BNEZC, "BNEZC rt,offset" },
+ { "BGEZL", &EmulateInstructionMIPS64::Emulate_BGEZL, "BGEZL rt,offset" },
+ { "BGTZ", &EmulateInstructionMIPS64::Emulate_BGTZ, "BGTZ rt,offset" },
+ { "BGTZL", &EmulateInstructionMIPS64::Emulate_BGTZL, "BGTZL rt,offset" },
+ { "BLEZ", &EmulateInstructionMIPS64::Emulate_BLEZ, "BLEZ rt,offset" },
+ { "BLEZL", &EmulateInstructionMIPS64::Emulate_BLEZL, "BLEZL rt,offset" },
+ { "BLTZ", &EmulateInstructionMIPS64::Emulate_BLTZ, "BLTZ rt,offset" },
+ { "BLTZAL", &EmulateInstructionMIPS64::Emulate_BLTZAL, "BLTZAL rt,offset" },
+ { "BLTZALL", &EmulateInstructionMIPS64::Emulate_BLTZALL, "BLTZALL rt,offset" },
+ { "BLTZL", &EmulateInstructionMIPS64::Emulate_BLTZL, "BLTZL rt,offset" },
+ { "BOVC", &EmulateInstructionMIPS64::Emulate_BOVC, "BOVC rs,rt,offset" },
+ { "BNVC", &EmulateInstructionMIPS64::Emulate_BNVC, "BNVC rs,rt,offset" },
+ { "J", &EmulateInstructionMIPS64::Emulate_J, "J target" },
+ { "JAL", &EmulateInstructionMIPS64::Emulate_JAL, "JAL target" },
+ { "JALX", &EmulateInstructionMIPS64::Emulate_JAL, "JALX target" },
+ { "JALR", &EmulateInstructionMIPS64::Emulate_JALR, "JALR target" },
+ { "JALR_HB", &EmulateInstructionMIPS64::Emulate_JALR, "JALR.HB target" },
+ { "JIALC", &EmulateInstructionMIPS64::Emulate_JIALC, "JIALC rt,offset" },
+ { "JIC", &EmulateInstructionMIPS64::Emulate_JIC, "JIC rt,offset" },
+ { "JR", &EmulateInstructionMIPS64::Emulate_JR, "JR target" },
+ { "JR_HB", &EmulateInstructionMIPS64::Emulate_JR, "JR.HB target" },
+ { "BC1F", &EmulateInstructionMIPS64::Emulate_BC1F, "BC1F cc, offset" },
+ { "BC1T", &EmulateInstructionMIPS64::Emulate_BC1T, "BC1T cc, offset" },
+ { "BC1FL", &EmulateInstructionMIPS64::Emulate_BC1FL, "BC1FL cc, offset" },
+ { "BC1TL", &EmulateInstructionMIPS64::Emulate_BC1TL, "BC1TL cc, offset" },
+ { "BC1EQZ", &EmulateInstructionMIPS64::Emulate_BC1EQZ, "BC1EQZ ft, offset" },
+ { "BC1NEZ", &EmulateInstructionMIPS64::Emulate_BC1NEZ, "BC1NEZ ft, offset" },
+ { "BC1ANY2F", &EmulateInstructionMIPS64::Emulate_BC1ANY2F, "BC1ANY2F cc, offset" },
+ { "BC1ANY2T", &EmulateInstructionMIPS64::Emulate_BC1ANY2T, "BC1ANY2T cc, offset" },
+ { "BC1ANY4F", &EmulateInstructionMIPS64::Emulate_BC1ANY4F, "BC1ANY4F cc, offset" },
+ { "BC1ANY4T", &EmulateInstructionMIPS64::Emulate_BC1ANY4T, "BC1ANY4T cc, offset" },
+ };
+
+ static const size_t k_num_mips_opcodes = llvm::array_lengthof(g_opcodes);
+
+ for (size_t i = 0; i < k_num_mips_opcodes; ++i)
+ {
+ if (! strcasecmp (g_opcodes[i].op_name, op_name))
+ return &g_opcodes[i];
+ }
+
+ return NULL;
+}
+
+bool
+EmulateInstructionMIPS64::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
+EmulateInstructionMIPS64::EvaluateInstruction (uint32_t evaluate_options)
+{
+ bool success = false;
+ llvm::MCInst mc_insn;
+ uint64_t insn_size;
+ DataExtractor data;
+
+ /* Keep the complexity of the decode logic with the llvm::MCDisassembler class. */
+ if (m_opcode.GetData (data))
+ {
+ llvm::MCDisassembler::DecodeStatus decode_status;
+ llvm::ArrayRef<uint8_t> raw_insn (data.GetDataStart(), data.GetByteSize());
+ decode_status = m_disasm->getInstruction (mc_insn, insn_size, raw_insn, m_addr, llvm::nulls(), llvm::nulls());
+ if (decode_status != llvm::MCDisassembler::Success)
+ return false;
+ }
+
+ /*
+ * mc_insn.getOpcode() returns decoded opcode. However to make use
+ * of llvm::Mips::<insn> we would need "MipsGenInstrInfo.inc".
+ */
+ const char *op_name = m_insn_info->getName (mc_insn.getOpcode ());
+
+ if (op_name == NULL)
+ return false;
+
+ /*
+ * Decoding has been done already. Just get the call-back function
+ * and emulate the instruction.
+ */
+ MipsOpcode *opcode_data = GetOpcodeForInstruction (op_name);
+
+ if (opcode_data == NULL)
+ return false;
+
+ uint64_t old_pc = 0, new_pc = 0;
+ const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
+
+ if (auto_advance_pc)
+ {
+ old_pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+ }
+
+ /* emulate instruction */
+ success = (this->*opcode_data->callback) (mc_insn);
+ if (!success)
+ return false;
+
+ if (auto_advance_pc)
+ {
+ new_pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ /* If we haven't changed the PC, change it here */
+ if (old_pc == new_pc)
+ {
+ new_pc += 4;
+ Context context;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, new_pc))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::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->GetCFAValue().SetIsRegisterPlusOffset(gcc_dwarf_sp_mips64, 0);
+
+ // Our previous PC is in the RA
+ row->SetRegisterLocationToRegister(gcc_dwarf_pc_mips64, gcc_dwarf_ra_mips64, can_replace);
+
+ unwind_plan.AppendRow (row);
+
+ // All other registers are the same.
+ unwind_plan.SetSourceName ("EmulateInstructionMIPS64");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::nonvolatile_reg_p (uint64_t regnum)
+{
+ switch (regnum)
+ {
+ case gcc_dwarf_r16_mips64:
+ case gcc_dwarf_r17_mips64:
+ case gcc_dwarf_r18_mips64:
+ case gcc_dwarf_r19_mips64:
+ case gcc_dwarf_r20_mips64:
+ case gcc_dwarf_r21_mips64:
+ case gcc_dwarf_r22_mips64:
+ case gcc_dwarf_r23_mips64:
+ case gcc_dwarf_gp_mips64:
+ case gcc_dwarf_sp_mips64:
+ case gcc_dwarf_r30_mips64:
+ case gcc_dwarf_ra_mips64:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_DADDiu (llvm::MCInst& insn)
+{
+ bool success = false;
+ const uint32_t imm16 = insn.getOperand(2).getImm();
+ uint64_t imm = SignedBits(imm16, 15, 0);
+ uint64_t result;
+ uint32_t src, dst;
+
+ dst = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ src = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+
+ /* Check if this is daddiu sp,<src>,imm16 */
+ if (dst == gcc_dwarf_sp_mips64)
+ {
+ /* read <src> register */
+ uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + src, 0, &success);
+ if (!success)
+ return false;
+
+ result = src_opd_val + imm;
+
+ Context context;
+ RegisterInfo reg_info_sp;
+ if (GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_sp_mips64, reg_info_sp))
+ context.SetRegisterPlusOffset (reg_info_sp, imm);
+
+ /* We are allocating bytes on stack */
+ context.type = eContextAdjustStackPointer;
+
+ WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_sp_mips64, result);
+ }
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_SD (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t imm16 = insn.getOperand(2).getImm();
+ uint64_t imm = SignedBits(imm16, 15, 0);
+ uint32_t src, base;
+
+ src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+
+ /* We look for sp based non-volatile register stores */
+ if (base == gcc_dwarf_sp_mips64 && nonvolatile_reg_p (src))
+ {
+ uint64_t address;
+ RegisterInfo reg_info_base;
+ RegisterInfo reg_info_src;
+
+ if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, reg_info_base)
+ || !GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + src, reg_info_src))
+ return false;
+
+ /* read SP */
+ address = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, 0, &success);
+ if (!success)
+ return false;
+
+ /* destination address */
+ address = address + imm;
+
+ Context context;
+ RegisterValue data_src;
+ context.type = eContextPushRegisterOnStack;
+ context.SetRegisterToRegisterPlusOffset (reg_info_src, reg_info_base, 0);
+
+ uint8_t buffer [RegisterValue::kMaxRegisterByteSize];
+ Error error;
+
+ if (!ReadRegister (&reg_info_base, data_src))
+ return false;
+
+ if (data_src.GetAsMemoryData (&reg_info_src, buffer, reg_info_src.byte_size, eByteOrderLittle, error) == 0)
+ return false;
+
+ if (!WriteMemory (context, address, buffer, reg_info_src.byte_size))
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_LD (llvm::MCInst& insn)
+{
+ uint32_t src, base;
+
+ src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+
+ if (base == gcc_dwarf_sp_mips64 && nonvolatile_reg_p (src))
+ {
+ RegisterValue data_src;
+ RegisterInfo reg_info_src;
+
+ if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + src, reg_info_src))
+ return false;
+
+ Context context;
+ context.type = eContextRegisterLoad;
+
+ if (!WriteRegister (context, &reg_info_src, data_src))
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BEQ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BEQ rs, rt, offset
+ * condition <- (GPR[rs] = GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ * else
+ * PC = PC + 4
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val == rt_val)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BNE (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BNE rs, rt, offset
+ * condition <- (GPR[rs] != GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val != rt_val)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BEQL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BEQL rs, rt, offset
+ * condition <- (GPR[rs] = GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val == rt_val)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BNEL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BNEL rs, rt, offset
+ * condition <- (GPR[rs] != GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val != rt_val)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGEZL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BGEZL rs, offset
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BLTZL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BLTZL rs, offset
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGTZL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BGTZL rs, offset
+ * condition <- (GPR[rs] > 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val > 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BLEZL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BLEZL rs, offset
+ * condition <- (GPR[rs] <= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val <= 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGTZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BGTZ rs, offset
+ * condition <- (GPR[rs] > 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val > 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BLEZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BLEZ rs, offset
+ * condition <- (GPR[rs] <= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val <= 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BLTZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BLTZ rs, offset
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGEZALL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BGEZALL rt, offset
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BAL (llvm::MCInst& insn)
+{
+ bool success = false;
+ int64_t offset, pc, target;
+
+ /*
+ * BAL offset
+ * offset = sign_ext (offset << 2)
+ * RA = PC + 8
+ * PC = PC + offset
+ */
+ offset = insn.getOperand(0).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ target = pc + offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ int64_t offset, pc, target;
+
+ /*
+ * BALC offset
+ * offset = sign_ext (offset << 2)
+ * RA = PC + 4
+ * PC = PC + 4 + offset
+ */
+ offset = insn.getOperand(0).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ target = pc + 4 + offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGEZAL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BGEZAL rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * RA = PC + 8
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if ((int64_t) rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BLTZAL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BLTZAL rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * RA = PC + 8
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if ((int64_t) rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BLTZALL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BLTZALL rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * RA = PC + 8
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 8))
+ return false;
+
+ return true;
+}
+
+
+bool
+EmulateInstructionMIPS64::Emulate_BLEZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BLEZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] <= 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val <= 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGEZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BGEZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BLTZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BLTZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGTZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BGTZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] > 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val > 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BEQZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target, rs_val;
+
+ /*
+ * BEQZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] == 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val == 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BNEZALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target, rs_val;
+
+ /*
+ * BNEZALC rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] != 0)
+ * if condition then
+ * RA = PC + 4
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val != 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGEZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target, rs_val;
+
+ /*
+ * BGEZ rs,offset
+ * offset = sign_ext (offset << 2)
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * PC = PC + offset
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BC (llvm::MCInst& insn)
+{
+ bool success = false;
+ int64_t offset, pc, target;
+
+ /*
+ * BC offset
+ * offset = sign_ext (offset << 2)
+ * PC = PC + 4 + offset
+ */
+ offset = insn.getOperand(0).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ target = pc + 4 + offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BEQC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BEQC rs, rt, offset
+ * condition <- (GPR[rs] = GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val == rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BNEC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target, rs_val, rt_val;
+
+ /*
+ * BNEC rs, rt, offset
+ * condition <- (GPR[rs] != GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val != rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BLTC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target;
+ int64_t rs_val, rt_val;
+
+ /*
+ * BLTC rs, rt, offset
+ * condition <- (GPR[rs] < GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val < rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGEC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target;
+ int64_t rs_val, rt_val;
+
+ /*
+ * BGEC rs, rt, offset
+ * condition <- (GPR[rs] > GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val > rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BLTUC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target;
+ uint64_t rs_val, rt_val;
+
+ /*
+ * BLTUC rs, rt, offset
+ * condition <- (GPR[rs] < GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val < rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGEUC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target;
+ uint64_t rs_val, rt_val;
+
+ /*
+ * BGEUC rs, rt, offset
+ * condition <- (GPR[rs] > GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val > rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BLTZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BLTZC rs, offset
+ * condition <- (GPR[rs] < 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val < 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BLEZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BLEZC rs, offset
+ * condition <- (GPR[rs] <= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val <= 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGEZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BGEZC rs, offset
+ * condition <- (GPR[rs] >= 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val >= 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BGTZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ int64_t rs_val;
+
+ /*
+ * BGTZC rs, offset
+ * condition <- (GPR[rs] > 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val > 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BEQZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ uint64_t rs_val;
+
+ /*
+ * BEQZC rs, offset
+ * condition <- (GPR[rs] = 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val == 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BNEZC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int64_t offset, pc, target;
+ uint64_t rs_val;
+
+ /*
+ * BNEZC rs, offset
+ * condition <- (GPR[rs] != 0)
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (rs_val != 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+static int
+IsAdd64bitOverflow (int64_t a, int64_t b)
+{
+ int64_t r = (uint64_t) a + (uint64_t) b;
+ return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0);
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BOVC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target;
+ int64_t rs_val, rt_val;
+
+ /*
+ * BOVC rs, rt, offset
+ * condition <- overflow(GPR[rs] + GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (IsAdd64bitOverflow (rs_val, rt_val))
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BNVC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int64_t offset, pc, target;
+ int64_t rs_val, rt_val;
+
+ /*
+ * BNVC rs, rt, offset
+ * condition <- overflow(GPR[rs] + GPR[rt])
+ * if condition then
+ * PC = PC + sign_ext (offset << 2)
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (! IsAdd64bitOverflow (rs_val, rt_val))
+ target = pc + offset;
+ else
+ target = pc + 4;
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_J (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint64_t offset, pc;
+
+ /*
+ * J offset
+ * offset = sign_ext (offset << 2)
+ * PC = PC[63-28] | offset
+ */
+ offset = insn.getOperand(0).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ /* This is a PC-region branch and not PC-relative */
+ pc = (pc & 0xFFFFFFFFF0000000ULL) | offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, pc))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_JAL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint64_t offset, target, pc;
+
+ /*
+ * JAL offset
+ * offset = sign_ext (offset << 2)
+ * PC = PC[63-28] | offset
+ */
+ offset = insn.getOperand(0).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ /* This is a PC-region branch and not PC-relative */
+ target = (pc & 0xFFFFFFFFF0000000ULL) | offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_JALR (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ uint64_t pc, rs_val;
+
+ /*
+ * JALR rt, rs
+ * GPR[rt] = PC + 8
+ * PC = GPR[rs]
+ */
+ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rs = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, rs_val))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, pc + 8))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_JIALC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rt;
+ int64_t target, offset, pc, rt_val;
+
+ /*
+ * JIALC rt, offset
+ * offset = sign_ext (offset)
+ * PC = GPR[rt] + offset
+ * RA = PC + 4
+ */
+ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ target = rt_val + offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 4))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_JIC (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rt;
+ int64_t target, offset, rt_val;
+
+ /*
+ * JIC rt, offset
+ * offset = sign_ext (offset)
+ * PC = GPR[rt] + offset
+ */
+ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rt, 0, &success);
+ if (!success)
+ return false;
+
+ target = rt_val + offset;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_JR (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ uint64_t rs_val;
+
+ /*
+ * JR rs
+ * PC = GPR[rs]
+ */
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+
+ rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + rs, 0, &success);
+ if (!success)
+ return false;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, rs_val))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BC1F (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int64_t target, pc, offset;
+
+ /*
+ * BC1F cc, offset
+ * condition <- (FPConditionCode(cc) == 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ if ((fcsr & (1 << cc)) == 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BC1T (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int64_t target, pc, offset;
+
+ /*
+ * BC1T cc, offset
+ * condition <- (FPConditionCode(cc) != 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ if ((fcsr & (1 << cc)) != 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BC1FL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int64_t target, pc, offset;
+
+ /*
+ * BC1F cc, offset
+ * condition <- (FPConditionCode(cc) == 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ if ((fcsr & (1 << cc)) == 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BC1TL (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int64_t target, pc, offset;
+
+ /*
+ * BC1T cc, offset
+ * condition <- (FPConditionCode(cc) != 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ if ((fcsr & (1 << cc)) != 0)
+ target = pc + offset;
+ else
+ target = pc + 8; /* skip delay slot */
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BC1EQZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t ft;
+ uint64_t ft_val;
+ int64_t target, pc, offset;
+
+ /*
+ * BC1EQZ ft, offset
+ * condition <- (FPR[ft].bit0 == 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + 4 + offset
+ */
+ ft = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ ft_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + ft, 0, &success);
+ if (!success)
+ return false;
+
+ if ((ft_val & 1) == 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BC1NEZ (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t ft;
+ uint64_t ft_val;
+ int64_t target, pc, offset;
+
+ /*
+ * BC1NEZ ft, offset
+ * condition <- (FPR[ft].bit0 != 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + 4 + offset
+ */
+ ft = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ ft_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + ft, 0, &success);
+ if (!success)
+ return false;
+
+ if ((ft_val & 1) != 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BC1ANY2F (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int64_t target, pc, offset;
+
+ /*
+ * BC1ANY2F cc, offset
+ * condition <- (FPConditionCode(cc) == 0
+ * || FPConditionCode(cc+1) == 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ /* if any one bit is 0 */
+ if (((fcsr >> cc) & 3) != 3)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BC1ANY2T (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int64_t target, pc, offset;
+
+ /*
+ * BC1ANY2T cc, offset
+ * condition <- (FPConditionCode(cc) == 1
+ * || FPConditionCode(cc+1) == 1)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ /* if any one bit is 1 */
+ if (((fcsr >> cc) & 3) != 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BC1ANY4F (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int64_t target, pc, offset;
+
+ /*
+ * BC1ANY4F cc, offset
+ * condition <- (FPConditionCode(cc) == 0
+ * || FPConditionCode(cc+1) == 0)
+ * || FPConditionCode(cc+2) == 0)
+ * || FPConditionCode(cc+3) == 0)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ /* if any one bit is 0 */
+ if (((fcsr >> cc) & 0xf) != 0xf)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_BC1ANY4T (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t cc, fcsr;
+ int64_t target, pc, offset;
+
+ /*
+ * BC1ANY4T cc, offset
+ * condition <- (FPConditionCode(cc) == 1
+ * || FPConditionCode(cc+1) == 1)
+ * || FPConditionCode(cc+2) == 1)
+ * || FPConditionCode(cc+3) == 1)
+ * if condition then
+ * offset = sign_ext (offset)
+ * PC = PC + offset
+ */
+ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_fcsr_mips64, 0, &success);
+ if (!success)
+ return false;
+
+ /* fcsr[23], fcsr[25-31] are vaild condition bits */
+ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
+
+ /* if any one bit is 1 */
+ if (((fcsr >> cc) & 0xf) != 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
+ return false;
+
+ return true;
+}
diff --git a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
new file mode 100644
index 000000000000..178417c196fa
--- /dev/null
+++ b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
@@ -0,0 +1,313 @@
+//===-- EmulateInstructionMIPS64.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef EmulateInstructionMIPS64_h_
+#define EmulateInstructionMIPS64_h_
+
+namespace llvm
+{
+ class MCDisassembler;
+ class MCSubtargetInfo;
+ class MCRegisterInfo;
+ class MCAsmInfo;
+ class MCContext;
+ class MCInstrInfo;
+ class MCInst;
+}
+
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+class EmulateInstructionMIPS64 : 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:
+ case lldb_private::eInstructionTypePCModifying:
+ return true;
+
+ 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);
+
+ EmulateInstructionMIPS64 (const lldb_private::ArchSpec &arch);
+
+ 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);
+
+
+protected:
+
+ typedef struct
+ {
+ const char *op_name;
+ bool (EmulateInstructionMIPS64::*callback) (llvm::MCInst& insn);
+ const char *insn_name;
+ } MipsOpcode;
+
+ static MipsOpcode*
+ GetOpcodeForInstruction (const char *op_name);
+
+ bool
+ Emulate_DADDiu (llvm::MCInst& insn);
+
+ bool
+ Emulate_SD (llvm::MCInst& insn);
+
+ bool
+ Emulate_LD (llvm::MCInst& insn);
+
+ bool
+ Emulate_BEQ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNE (llvm::MCInst& insn);
+
+ bool
+ Emulate_BEQL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNEL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZALL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BAL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZAL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLEZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGTZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BEQZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNEZALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BEQC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNEC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTUC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEUC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLEZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGTZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BEQZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNEZC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGEZL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGTZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BGTZL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLEZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLEZL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZAL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZALL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BLTZL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BOVC (llvm::MCInst& insn);
+
+ bool
+ Emulate_BNVC (llvm::MCInst& insn);
+
+ bool
+ Emulate_J (llvm::MCInst& insn);
+
+ bool
+ Emulate_JAL (llvm::MCInst& insn);
+
+ bool
+ Emulate_JALR (llvm::MCInst& insn);
+
+ bool
+ Emulate_JIALC (llvm::MCInst& insn);
+
+ bool
+ Emulate_JIC (llvm::MCInst& insn);
+
+ bool
+ Emulate_JR (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1F (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1T (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1FL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1TL (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1EQZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1NEZ (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1ANY2F (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1ANY2T (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1ANY4F (llvm::MCInst& insn);
+
+ bool
+ Emulate_BC1ANY4T (llvm::MCInst& insn);
+
+ bool
+ nonvolatile_reg_p (uint64_t regnum);
+
+ const char *
+ GetRegisterName (unsigned reg_num, bool altnernate_name);
+
+private:
+ std::unique_ptr<llvm::MCDisassembler> m_disasm;
+ std::unique_ptr<llvm::MCSubtargetInfo> m_subtype_info;
+ std::unique_ptr<llvm::MCRegisterInfo> m_reg_info;
+ std::unique_ptr<llvm::MCAsmInfo> m_asm_info;
+ std::unique_ptr<llvm::MCContext> m_context;
+ std::unique_ptr<llvm::MCInstrInfo> m_insn_info;
+};
+
+#endif // EmulateInstructionMIPS64_h_
diff --git a/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp b/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp
index 96754ff78787..9b72ceb71bd0 100644
--- a/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp
+++ b/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp
@@ -13,6 +13,7 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Stream.h"
@@ -130,26 +131,34 @@ AddressSanitizerRuntime::IsActive()
const char *
address_sanitizer_retrieve_report_data_command = R"(
- struct {
- int present;
- void *pc, *bp, *sp, *address;
- int access_type;
- size_t access_size;
- const char *description;
- } t;
+int __asan_report_present();
+void *__asan_get_report_pc();
+void *__asan_get_report_bp();
+void *__asan_get_report_sp();
+void *__asan_get_report_address();
+const char *__asan_get_report_description();
+int __asan_get_report_access_type();
+size_t __asan_get_report_access_size();
+struct {
+ int present;
+ int access_type;
+ void *pc;
+ void *bp;
+ void *sp;
+ void *address;
+ size_t access_size;
+ const char *description;
+} t;
- t.present = ((int (*) ())__asan_report_present)();
- t.pc = ((void * (*) ())__asan_get_report_pc)();
- /* commented out because rdar://problem/18533301
- t.bp = ((void * (*) ())__asan_get_report_bp)();
- t.sp = ((void * (*) ())__asan_get_report_sp)();
- */
- t.address = ((void * (*) ())__asan_get_report_address)();
- t.description = ((const char * (*) ())__asan_get_report_description)();
- t.access_type = ((int (*) ())__asan_get_report_access_type)();
- t.access_size = ((size_t (*) ())__asan_get_report_access_size)();
-
- t;
+t.present = __asan_report_present();
+t.access_type = __asan_get_report_access_type();
+t.pc = __asan_get_report_pc();
+t.bp = __asan_get_report_bp();
+t.sp = __asan_get_report_sp();
+t.address = __asan_get_report_address();
+t.access_size = __asan_get_report_access_size();
+t.description = __asan_get_report_description();
+t
)";
StructuredData::ObjectSP
@@ -177,8 +186,10 @@ AddressSanitizerRuntime::RetrieveReportData()
return StructuredData::ObjectSP();
addr_t pc = return_value_sp->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0);
+ /* commented out because rdar://problem/18533301
addr_t bp = return_value_sp->GetValueForExpressionPath(".bp")->GetValueAsUnsigned(0);
addr_t sp = return_value_sp->GetValueForExpressionPath(".sp")->GetValueAsUnsigned(0);
+ */
addr_t address = return_value_sp->GetValueForExpressionPath(".address")->GetValueAsUnsigned(0);
addr_t access_type = return_value_sp->GetValueForExpressionPath(".access_type")->GetValueAsUnsigned(0);
addr_t access_size = return_value_sp->GetValueForExpressionPath(".access_size")->GetValueAsUnsigned(0);
@@ -191,8 +202,10 @@ AddressSanitizerRuntime::RetrieveReportData()
dict->AddStringItem("instrumentation_class", "AddressSanitizer");
dict->AddStringItem("stop_type", "fatal_error");
dict->AddIntegerItem("pc", pc);
+ /* commented out because rdar://problem/18533301
dict->AddIntegerItem("bp", bp);
dict->AddIntegerItem("sp", sp);
+ */
dict->AddIntegerItem("address", address);
dict->AddIntegerItem("access_type", access_type);
dict->AddIntegerItem("access_size", access_size);
@@ -274,11 +287,11 @@ AddressSanitizerRuntime::Activate()
if (symbol == NULL)
return;
- if (!symbol->GetAddress().IsValid())
+ if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
return;
Target &target = m_process->GetTarget();
- addr_t symbol_address = symbol->GetAddress().GetOpcodeLoadAddress(&target);
+ addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
if (symbol_address == LLDB_INVALID_ADDRESS)
return;
diff --git a/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
index cd303cb0768f..8e454e712fe8 100644
--- a/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
+++ b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
@@ -16,10 +16,11 @@
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
-#include "lldb/Symbol/SymbolVendor.h"
#include "JITLoaderGDB.h"
@@ -435,10 +436,10 @@ JITLoaderGDB::GetSymbolAddress(ModuleList &module_list, const ConstString &name,
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())
+ const Address jit_descriptor_addr = sym_ctx.symbol->GetAddress();
+ if (!jit_descriptor_addr.IsValid())
return LLDB_INVALID_ADDRESS;
- const addr_t jit_addr = jit_descriptor_addr->GetLoadAddress(&target);
+ const addr_t jit_addr = jit_descriptor_addr.GetLoadAddress(&target);
return jit_addr;
}
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
index 50537eb119f2..7d21b779ebd2 100644
--- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -281,6 +281,46 @@ ItaniumABILanguageRuntime::IsVTableName (const char *name)
return false;
}
+static std::map<ConstString, std::vector<ConstString> >&
+GetAlternateManglingPrefixes()
+{
+ static std::map<ConstString, std::vector<ConstString> > g_alternate_mangling_prefixes;
+ return g_alternate_mangling_prefixes;
+}
+
+
+size_t
+ItaniumABILanguageRuntime::GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates)
+{
+ if (!mangled)
+ return static_cast<size_t>(0);
+
+ alternates.clear();
+ const char *mangled_cstr = mangled.AsCString();
+ std::map<ConstString, std::vector<ConstString> >& alternate_mangling_prefixes = GetAlternateManglingPrefixes();
+ for (std::map<ConstString, std::vector<ConstString> >::iterator it = alternate_mangling_prefixes.begin();
+ it != alternate_mangling_prefixes.end();
+ ++it)
+ {
+ const char *prefix_cstr = it->first.AsCString();
+ if (strncmp(mangled_cstr, prefix_cstr, strlen(prefix_cstr)) == 0)
+ {
+ const std::vector<ConstString> &alternate_prefixes = it->second;
+ for (size_t i = 0; i < alternate_prefixes.size(); ++i)
+ {
+ std::string alternate_mangling(alternate_prefixes[i].AsCString());
+ alternate_mangling.append(mangled_cstr + strlen(prefix_cstr));
+
+ alternates.push_back(ConstString(alternate_mangling.c_str()));
+ }
+
+ return alternates.size();
+ }
+ }
+
+ return static_cast<size_t>(0);
+}
+
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
@@ -304,6 +344,17 @@ ItaniumABILanguageRuntime::Initialize()
PluginManager::RegisterPlugin (GetPluginNameStatic(),
"Itanium ABI for the C++ language",
CreateInstance);
+
+ // Alternate manglings for std::basic_string<...>
+ std::vector<ConstString> basic_string_alternates;
+ basic_string_alternates.push_back(ConstString("_ZNSs"));
+ basic_string_alternates.push_back(ConstString("_ZNKSs"));
+ std::map<ConstString, std::vector<ConstString> >& alternate_mangling_prefixes = GetAlternateManglingPrefixes();
+
+ alternate_mangling_prefixes[ConstString("_ZNSbIcSt17char_traits<char>St15allocator<char>E")] =
+ basic_string_alternates;
+ alternate_mangling_prefixes[ConstString("_ZNKSbIcSt17char_traits<char>St15allocator<char>E")] =
+ basic_string_alternates;
}
void
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
index cd0a4b2c15eb..bc5d83be4bf5 100644
--- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
@@ -20,6 +20,9 @@
#include "lldb/Target/CPPLanguageRuntime.h"
#include "lldb/Core/Value.h"
+#include <map>
+#include <vector>
+
namespace lldb_private {
class ItaniumABILanguageRuntime :
@@ -82,6 +85,9 @@ namespace lldb_private {
virtual lldb::SearchFilterSP
CreateExceptionSearchFilter ();
+ virtual size_t
+ GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates);
+
protected:
lldb::BreakpointResolverSP
diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
new file mode 100644
index 000000000000..2490cf31409b
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
@@ -0,0 +1,1191 @@
+//===-- RenderScriptRuntime.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RenderScriptRuntime.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "lldb/Symbol/VariableList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+LanguageRuntime *
+RenderScriptRuntime::CreateInstance(Process *process, lldb::LanguageType language)
+{
+
+ if (language == eLanguageTypeExtRenderScript)
+ return new RenderScriptRuntime(process);
+ else
+ return NULL;
+}
+
+void
+RenderScriptRuntime::Initialize()
+{
+ PluginManager::RegisterPlugin(GetPluginNameStatic(), "RenderScript language support", CreateInstance, GetCommandObject);
+}
+
+void
+RenderScriptRuntime::Terminate()
+{
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb_private::ConstString
+RenderScriptRuntime::GetPluginNameStatic()
+{
+ static ConstString g_name("renderscript");
+ return g_name;
+}
+
+RenderScriptRuntime::ModuleKind
+RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp)
+{
+ if (module_sp)
+ {
+ // Is this a module containing renderscript kernels?
+ const Symbol *info_sym = module_sp->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData);
+ if (info_sym)
+ {
+ return eModuleKindKernelObj;
+ }
+
+ // Is this the main RS runtime library
+ const ConstString rs_lib("libRS.so");
+ if (module_sp->GetFileSpec().GetFilename() == rs_lib)
+ {
+ return eModuleKindLibRS;
+ }
+
+ const ConstString rs_driverlib("libRSDriver.so");
+ if (module_sp->GetFileSpec().GetFilename() == rs_driverlib)
+ {
+ return eModuleKindDriver;
+ }
+
+ const ConstString rs_cpureflib("libRSCPURef.so");
+ if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib)
+ {
+ return eModuleKindImpl;
+ }
+
+ }
+ return eModuleKindIgnored;
+}
+
+bool
+RenderScriptRuntime::IsRenderScriptModule(const lldb::ModuleSP &module_sp)
+{
+ return GetModuleKind(module_sp) != eModuleKindIgnored;
+}
+
+
+void
+RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list )
+{
+ Mutex::Locker locker (module_list.GetMutex ());
+
+ size_t num_modules = module_list.GetSize();
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ auto mod = module_list.GetModuleAtIndex (i);
+ if (IsRenderScriptModule (mod))
+ {
+ LoadModule(mod);
+ }
+ }
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+RenderScriptRuntime::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+RenderScriptRuntime::GetPluginVersion()
+{
+ return 1;
+}
+
+bool
+RenderScriptRuntime::IsVTableName(const char *name)
+{
+ return false;
+}
+
+bool
+RenderScriptRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic,
+ TypeAndOrName &class_type_or_name, Address &address)
+{
+ return false;
+}
+
+bool
+RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value)
+{
+ return false;
+}
+
+lldb::BreakpointResolverSP
+RenderScriptRuntime::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp)
+{
+ BreakpointResolverSP resolver_sp;
+ return resolver_sp;
+}
+
+
+const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] =
+{
+ //rsdScript
+ {"rsdScriptInit", "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_7ScriptCEPKcS7_PKhjj", 0, RenderScriptRuntime::eModuleKindDriver, &lldb_private::RenderScriptRuntime::CaptureScriptInit1},
+ {"rsdScriptInvokeForEach", "_Z22rsdScriptInvokeForEachPKN7android12renderscript7ContextEPNS0_6ScriptEjPKNS0_10AllocationEPS6_PKvjPK12RsScriptCall", 0, RenderScriptRuntime::eModuleKindDriver, nullptr},
+ {"rsdScriptInvokeForEachMulti", "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall", 0, RenderScriptRuntime::eModuleKindDriver, nullptr},
+ {"rsdScriptInvokeFunction", "_Z23rsdScriptInvokeFunctionPKN7android12renderscript7ContextEPNS0_6ScriptEjPKvj", 0, RenderScriptRuntime::eModuleKindDriver, nullptr},
+ {"rsdScriptSetGlobalVar", "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_6ScriptEjPvj", 0, RenderScriptRuntime::eModuleKindDriver, &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar1},
+
+ //rsdAllocation
+ {"rsdAllocationInit", "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_10AllocationEb", 0, RenderScriptRuntime::eModuleKindDriver, &lldb_private::RenderScriptRuntime::CaptureAllocationInit1},
+ {"rsdAllocationRead2D", "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_10AllocationEjjj23RsAllocationCubemapFacejjPvjj", 0, RenderScriptRuntime::eModuleKindDriver, nullptr},
+};
+const size_t RenderScriptRuntime::s_runtimeHookCount = sizeof(s_runtimeHookDefns)/sizeof(s_runtimeHookDefns[0]);
+
+
+bool
+RenderScriptRuntime::HookCallback(void *baton, StoppointCallbackContext *ctx, lldb::user_id_t break_id, lldb::user_id_t break_loc_id)
+{
+ RuntimeHook* hook_info = (RuntimeHook*)baton;
+ ExecutionContext context(ctx->exe_ctx_ref);
+
+ RenderScriptRuntime *lang_rt = (RenderScriptRuntime *)context.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
+
+ lang_rt->HookCallback(hook_info, context);
+
+ return false;
+}
+
+
+void
+RenderScriptRuntime::HookCallback(RuntimeHook* hook_info, ExecutionContext& context)
+{
+ Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
+
+ if(log)
+ log->Printf ("RenderScriptRuntime::HookCallback - '%s' .", hook_info->defn->name);
+
+ if (hook_info->defn->grabber)
+ {
+ (this->*(hook_info->defn->grabber))(hook_info, context);
+ }
+}
+
+
+bool
+RenderScriptRuntime::GetArg32Simple(ExecutionContext& context, uint32_t arg, uint32_t *data)
+{
+ Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
+
+ if (!data)
+ return false;
+
+ Error error;
+ RegisterContext* reg_ctx = context.GetRegisterContext();
+ Process* process = context.GetProcessPtr();
+
+ if (context.GetTargetPtr()->GetArchitecture().GetMachine() == llvm::Triple::ArchType::x86)
+ {
+ uint64_t sp = reg_ctx->GetSP();
+ {
+ uint32_t offset = (1 + arg) * sizeof(uint32_t);
+ process->ReadMemory(sp + offset, data, sizeof(uint32_t), error);
+ if(error.Fail())
+ {
+ if(log)
+ log->Printf ("RenderScriptRuntime:: GetArg32Simple - error reading X86 stack: %s.", error.AsCString());
+ }
+ }
+ }
+ else if (context.GetTargetPtr()->GetArchitecture().GetMachine() == llvm::Triple::ArchType::arm)
+ {
+ if (arg < 4)
+ {
+ const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg);
+ RegisterValue rVal;
+ reg_ctx->ReadRegister(rArg, rVal);
+ (*data) = rVal.GetAsUInt32();
+ }
+ else
+ {
+ uint64_t sp = reg_ctx->GetSP();
+ {
+ uint32_t offset = (arg-4) * sizeof(uint32_t);
+ process->ReadMemory(sp + offset, &data, sizeof(uint32_t), error);
+ if(error.Fail())
+ {
+ if(log)
+ log->Printf ("RenderScriptRuntime:: GetArg32Simple - error reading ARM stack: %s.", error.AsCString());
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void
+RenderScriptRuntime::CaptureSetGlobalVar1(RuntimeHook* hook_info, ExecutionContext& context)
+{
+ Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
+
+ //Context, Script, int, data, length
+
+ Error error;
+
+ uint32_t rs_context_u32 = 0U;
+ uint32_t rs_script_u32 = 0U;
+ uint32_t rs_id_u32 = 0U;
+ uint32_t rs_data_u32 = 0U;
+ uint32_t rs_length_u32 = 0U;
+
+ std::string resname;
+ std::string cachedir;
+
+ GetArg32Simple(context, 0, &rs_context_u32);
+ GetArg32Simple(context, 1, &rs_script_u32);
+ GetArg32Simple(context, 2, &rs_id_u32);
+ GetArg32Simple(context, 3, &rs_data_u32);
+ GetArg32Simple(context, 4, &rs_length_u32);
+
+ if(log)
+ {
+ log->Printf ("RenderScriptRuntime::CaptureSetGlobalVar1 - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64 ":%" PRIu64 "bytes.",
+ (uint64_t)rs_context_u32, (uint64_t)rs_script_u32, (uint64_t)rs_id_u32, (uint64_t)rs_data_u32, (uint64_t)rs_length_u32);
+
+ addr_t script_addr = (addr_t)rs_script_u32;
+ if (m_scriptMappings.find( script_addr ) != m_scriptMappings.end())
+ {
+ auto rsm = m_scriptMappings[script_addr];
+ if (rs_id_u32 < rsm->m_globals.size())
+ {
+ auto rsg = rsm->m_globals[rs_id_u32];
+ log->Printf ("RenderScriptRuntime::CaptureSetGlobalVar1 - Setting of '%s' within '%s' inferred", rsg.m_name.AsCString(),
+ rsm->m_module->GetFileSpec().GetFilename().AsCString());
+ }
+ }
+ }
+}
+
+void
+RenderScriptRuntime::CaptureAllocationInit1(RuntimeHook* hook_info, ExecutionContext& context)
+{
+ Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
+
+ //Context, Alloc, bool
+
+ Error error;
+
+ uint32_t rs_context_u32 = 0U;
+ uint32_t rs_alloc_u32 = 0U;
+ uint32_t rs_forceZero_u32 = 0U;
+
+ GetArg32Simple(context, 0, &rs_context_u32);
+ GetArg32Simple(context, 1, &rs_alloc_u32);
+ GetArg32Simple(context, 2, &rs_forceZero_u32);
+
+ if(log)
+ log->Printf ("RenderScriptRuntime::CaptureAllocationInit1 - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .",
+ (uint64_t)rs_context_u32, (uint64_t)rs_alloc_u32, (uint64_t)rs_forceZero_u32);
+}
+
+void
+RenderScriptRuntime::CaptureScriptInit1(RuntimeHook* hook_info, ExecutionContext& context)
+{
+ Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
+
+ //Context, Script, resname Str, cachedir Str
+ Error error;
+ Process* process = context.GetProcessPtr();
+
+ uint32_t rs_context_u32 = 0U;
+ uint32_t rs_script_u32 = 0U;
+ uint32_t rs_resnameptr_u32 = 0U;
+ uint32_t rs_cachedirptr_u32 = 0U;
+
+ std::string resname;
+ std::string cachedir;
+
+ GetArg32Simple(context, 0, &rs_context_u32);
+ GetArg32Simple(context, 1, &rs_script_u32);
+ GetArg32Simple(context, 2, &rs_resnameptr_u32);
+ GetArg32Simple(context, 3, &rs_cachedirptr_u32);
+
+ process->ReadCStringFromMemory((lldb::addr_t)rs_resnameptr_u32, resname, error);
+ if (error.Fail())
+ {
+ if(log)
+ log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - error reading resname: %s.", error.AsCString());
+
+ }
+
+ process->ReadCStringFromMemory((lldb::addr_t)rs_cachedirptr_u32, cachedir, error);
+ if (error.Fail())
+ {
+ if(log)
+ log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - error reading cachedir: %s.", error.AsCString());
+ }
+
+ if (log)
+ log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .",
+ (uint64_t)rs_context_u32, (uint64_t)rs_script_u32, resname.c_str(), cachedir.c_str());
+
+ if (resname.size() > 0)
+ {
+ StreamString strm;
+ strm.Printf("librs.%s.so", resname.c_str());
+
+ ScriptDetails script;
+ script.cachedir = cachedir;
+ script.resname = resname;
+ script.scriptDyLib.assign(strm.GetData());
+ script.script = rs_script_u32;
+ script.context = rs_context_u32;
+
+ m_scripts.push_back(script);
+
+ if (log)
+ log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - '%s' tagged with context 0x%" PRIx64 " and script 0x%" PRIx64 ".",
+ strm.GetData(), (uint64_t)rs_context_u32, (uint64_t)rs_script_u32);
+ }
+ else if (log)
+ {
+ log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - resource name invalid, Script not tagged");
+ }
+
+}
+
+
+void
+RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind)
+{
+ Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
+
+ if (!module)
+ {
+ return;
+ }
+
+ if ((GetProcess()->GetTarget().GetArchitecture().GetMachine() != llvm::Triple::ArchType::x86)
+ && (GetProcess()->GetTarget().GetArchitecture().GetMachine() != llvm::Triple::ArchType::arm))
+ {
+ if (log)
+ log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Unable to hook runtime. Only X86, ARM supported currently.");
+
+ return;
+ }
+
+ Target &target = GetProcess()->GetTarget();
+
+ for (size_t idx = 0; idx < s_runtimeHookCount; idx++)
+ {
+ const HookDefn* hook_defn = &s_runtimeHookDefns[idx];
+ if (hook_defn->kind != kind) {
+ continue;
+ }
+
+ const Symbol *sym = module->FindFirstSymbolWithNameAndType(ConstString(hook_defn->symbol_name), eSymbolTypeCode);
+
+ addr_t addr = sym->GetLoadAddress(&target);
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ if(log)
+ log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Unable to resolve the address of hook function '%s' with symbol '%s'.",
+ hook_defn->name, hook_defn->symbol_name);
+ continue;
+ }
+
+ RuntimeHookSP hook(new RuntimeHook());
+ hook->address = addr;
+ hook->defn = hook_defn;
+ hook->bp_sp = target.CreateBreakpoint(addr, true, false);
+ hook->bp_sp->SetCallback(HookCallback, hook.get(), true);
+ m_runtimeHooks[addr] = hook;
+ if (log)
+ {
+ log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Successfully hooked '%s' in '%s' version %" PRIu64 " at 0x%" PRIx64 ".",
+ hook_defn->name, module->GetFileSpec().GetFilename().AsCString(), (uint64_t)hook_defn->version, (uint64_t)addr);
+ }
+ }
+}
+
+void
+RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp)
+{
+ if (!rsmodule_sp)
+ return;
+
+ Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
+
+ const ModuleSP module = rsmodule_sp->m_module;
+ const FileSpec& file = module->GetPlatformFileSpec();
+
+ for (const auto &rs_script : m_scripts)
+ {
+ if (file.GetFilename() == ConstString(rs_script.scriptDyLib.c_str()))
+ {
+ if (m_scriptMappings.find( rs_script.script ) != m_scriptMappings.end())
+ {
+ if (m_scriptMappings[rs_script.script] != rsmodule_sp)
+ {
+ if (log)
+ {
+ log->Printf ("RenderScriptRuntime::FixupScriptDetails - Error: script %" PRIx64 " wants reassigned to new rsmodule '%s'.",
+ (uint64_t)rs_script.script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
+ }
+ }
+ }
+ else
+ {
+ m_scriptMappings[rs_script.script] = rsmodule_sp;
+ rsmodule_sp->m_resname = rs_script.resname;
+ if (log)
+ {
+ log->Printf ("RenderScriptRuntime::FixupScriptDetails - script %" PRIx64 " associated with rsmodule '%s'.",
+ (uint64_t)rs_script.script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
+ }
+ }
+ }
+ }
+
+}
+
+bool
+RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp)
+{
+ Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
+
+ if (module_sp)
+ {
+ for (const auto &rs_module : m_rsmodules)
+ {
+ if (rs_module->m_module == module_sp)
+ return false;
+ }
+ bool module_loaded = false;
+ switch (GetModuleKind(module_sp))
+ {
+ case eModuleKindKernelObj:
+ {
+ RSModuleDescriptorSP module_desc;
+ module_desc.reset(new RSModuleDescriptor(module_sp));
+ if (module_desc->ParseRSInfo())
+ {
+ m_rsmodules.push_back(module_desc);
+ module_loaded = true;
+ }
+ if (module_loaded)
+ {
+ FixupScriptDetails(module_desc);
+ }
+ break;
+ }
+ case eModuleKindDriver:
+ {
+ if (!m_libRSDriver)
+ {
+ m_libRSDriver = module_sp;
+ LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver);
+ }
+ break;
+ }
+ case eModuleKindImpl:
+ {
+ m_libRSCpuRef = module_sp;
+ break;
+ }
+ case eModuleKindLibRS:
+ {
+ if (!m_libRS)
+ {
+ m_libRS = module_sp;
+ static ConstString gDbgPresentStr("gDebuggerPresent");
+ const Symbol* debug_present = m_libRS->FindFirstSymbolWithNameAndType(gDbgPresentStr, eSymbolTypeData);
+ if (debug_present)
+ {
+ Error error;
+ uint32_t flag = 0x00000001U;
+ Target &target = GetProcess()->GetTarget();
+ addr_t addr = debug_present->GetLoadAddress(&target);
+ GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error);
+ if(error.Success())
+ {
+ if (log)
+ log->Printf ("RenderScriptRuntime::LoadModule - Debugger present flag set on debugee");
+
+ m_debuggerPresentFlagged = true;
+ }
+ else if (log)
+ {
+ log->Printf ("RenderScriptRuntime::LoadModule - Error writing debugger present flags '%s' ", error.AsCString());
+ }
+ }
+ else if (log)
+ {
+ log->Printf ("RenderScriptRuntime::LoadModule - Error writing debugger present flags - symbol not found");
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (module_loaded)
+ Update();
+ return module_loaded;
+ }
+ return false;
+}
+
+void
+RenderScriptRuntime::Update()
+{
+ if (m_rsmodules.size() > 0)
+ {
+ if (!m_initiated)
+ {
+ Initiate();
+ }
+ }
+}
+
+
+// The maximum line length of an .rs.info packet
+#define MAXLINE 500
+
+// The .rs.info symbol in renderscript modules contains a string which needs to be parsed.
+// The string is basic and is parsed on a line by line basis.
+bool
+RSModuleDescriptor::ParseRSInfo()
+{
+ const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData);
+ if (info_sym)
+ {
+ const addr_t addr = info_sym->GetAddressRef().GetFileAddress();
+ const addr_t size = info_sym->GetByteSize();
+ const FileSpec fs = m_module->GetFileSpec();
+
+ DataBufferSP buffer = fs.ReadFileContents(addr, size);
+
+ if (!buffer)
+ return false;
+
+ std::string info((const char *)buffer->GetBytes());
+
+ std::vector<std::string> info_lines;
+ size_t lpos = info.find_first_of("\n");
+ while (lpos != std::string::npos)
+ {
+ info_lines.push_back(info.substr(0, lpos));
+ info = info.substr(lpos + 1);
+ lpos = info.find_first_of("\n");
+ }
+ size_t offset = 0;
+ while (offset < info_lines.size())
+ {
+ std::string line = info_lines[offset];
+ // Parse directives
+ uint32_t numDefns = 0;
+ if (sscanf(line.c_str(), "exportVarCount: %u", &numDefns) == 1)
+ {
+ while (numDefns--)
+ m_globals.push_back(RSGlobalDescriptor(this, info_lines[++offset].c_str()));
+ }
+ else if (sscanf(line.c_str(), "exportFuncCount: %u", &numDefns) == 1)
+ {
+ }
+ else if (sscanf(line.c_str(), "exportForEachCount: %u", &numDefns) == 1)
+ {
+ char name[MAXLINE];
+ while (numDefns--)
+ {
+ uint32_t slot = 0;
+ name[0] = '\0';
+ if (sscanf(info_lines[++offset].c_str(), "%u - %s", &slot, &name[0]) == 2)
+ {
+ m_kernels.push_back(RSKernelDescriptor(this, name, slot));
+ }
+ }
+ }
+ else if (sscanf(line.c_str(), "pragmaCount: %u", &numDefns) == 1)
+ {
+ char name[MAXLINE];
+ char value[MAXLINE];
+ while (numDefns--)
+ {
+ name[0] = '\0';
+ value[0] = '\0';
+ if (sscanf(info_lines[++offset].c_str(), "%s - %s", &name[0], &value[0]) != 0
+ && (name[0] != '\0'))
+ {
+ m_pragmas[std::string(name)] = value;
+ }
+ }
+ }
+ else if (sscanf(line.c_str(), "objectSlotCount: %u", &numDefns) == 1)
+ {
+ }
+
+ offset++;
+ }
+ return m_kernels.size() > 0;
+ }
+ return false;
+}
+
+bool
+RenderScriptRuntime::ProbeModules(const ModuleList module_list)
+{
+ bool rs_found = false;
+ size_t num_modules = module_list.GetSize();
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ auto module = module_list.GetModuleAtIndex(i);
+ rs_found |= LoadModule(module);
+ }
+ return rs_found;
+}
+
+void
+RenderScriptRuntime::Status(Stream &strm) const
+{
+ if (m_libRS)
+ {
+ strm.Printf("Runtime Library discovered.");
+ strm.EOL();
+ }
+ if (m_libRSDriver)
+ {
+ strm.Printf("Runtime Driver discovered.");
+ strm.EOL();
+ }
+ if (m_libRSCpuRef)
+ {
+ strm.Printf("CPU Reference Implementation discovered.");
+ strm.EOL();
+ }
+
+ if (m_runtimeHooks.size())
+ {
+ strm.Printf("Runtime functions hooked:");
+ strm.EOL();
+ for (auto b : m_runtimeHooks)
+ {
+ strm.Indent(b.second->defn->name);
+ strm.EOL();
+ }
+ strm.EOL();
+ }
+ else
+ {
+ strm.Printf("Runtime is not hooked.");
+ strm.EOL();
+ }
+}
+
+void
+RenderScriptRuntime::DumpContexts(Stream &strm) const
+{
+ strm.Printf("Inferred RenderScript Contexts:");
+ strm.EOL();
+ strm.IndentMore();
+
+ std::map<addr_t, uint64_t> contextReferences;
+
+ for (const auto &script : m_scripts)
+ {
+ if (contextReferences.find(script.context) != contextReferences.end())
+ {
+ contextReferences[script.context]++;
+ }
+ else
+ {
+ contextReferences[script.context] = 1;
+ }
+ }
+
+ for (const auto& cRef : contextReferences)
+ {
+ strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", cRef.first, cRef.second);
+ strm.EOL();
+ }
+ strm.IndentLess();
+}
+
+void
+RenderScriptRuntime::DumpKernels(Stream &strm) const
+{
+ strm.Printf("RenderScript Kernels:");
+ strm.EOL();
+ strm.IndentMore();
+ for (const auto &module : m_rsmodules)
+ {
+ strm.Printf("Resource '%s':",module->m_resname.c_str());
+ strm.EOL();
+ for (const auto &kernel : module->m_kernels)
+ {
+ strm.Indent(kernel.m_name.AsCString());
+ strm.EOL();
+ }
+ }
+ strm.IndentLess();
+}
+
+void
+RenderScriptRuntime::AttemptBreakpointAtKernelName(Stream &strm, const char* name, Error& error)
+{
+ if (!name)
+ {
+ error.SetErrorString("invalid kernel name");
+ return;
+ }
+
+ bool kernels_found;
+ ConstString kernel_name(name);
+ for (const auto &module : m_rsmodules)
+ {
+ for (const auto &kernel : module->m_kernels)
+ {
+ if (kernel.m_name == kernel_name)
+ {
+ //Attempt to set a breakpoint on this symbol, within the module library
+ //If it's not found, it's likely debug info is unavailable - set a
+ //breakpoint on <name>.expand and emit a warning.
+
+ const Symbol* kernel_sym = module->m_module->FindFirstSymbolWithNameAndType(kernel_name, eSymbolTypeCode);
+
+ if (!kernel_sym)
+ {
+ std::string kernel_name_expanded(name);
+ kernel_name_expanded.append(".expand");
+ kernel_sym = module->m_module->FindFirstSymbolWithNameAndType(ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode);
+
+ if (kernel_sym)
+ {
+ strm.Printf("Kernel '%s' could not be found, but expansion exists. ", name);
+ strm.Printf("Breakpoint placed on expanded kernel. Have you compiled in debug mode?");
+ strm.EOL();
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("Could not locate symbols for loaded kernel '%s'.", name);
+ return;
+ }
+ }
+
+ addr_t bp_addr = kernel_sym->GetLoadAddress(&GetProcess()->GetTarget());
+ if (bp_addr == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorStringWithFormat("Could not locate load address for symbols of kernel '%s'.", name);
+ return;
+ }
+
+ BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(bp_addr, false, false);
+ strm.Printf("Breakpoint %" PRIu64 ": kernel '%s' within script '%s'", (uint64_t)bp->GetID(), name, module->m_resname.c_str());
+ strm.EOL();
+
+ kernels_found = true;
+ }
+ }
+ }
+
+ if (!kernels_found)
+ {
+ error.SetErrorString("kernel name not found");
+ }
+ return;
+}
+
+void
+RenderScriptRuntime::DumpModules(Stream &strm) const
+{
+ strm.Printf("RenderScript Modules:");
+ strm.EOL();
+ strm.IndentMore();
+ for (const auto &module : m_rsmodules)
+ {
+ module->Dump(strm);
+ }
+ strm.IndentLess();
+}
+
+void
+RSModuleDescriptor::Dump(Stream &strm) const
+{
+ strm.Indent();
+ m_module->GetFileSpec().Dump(&strm);
+ m_module->ParseAllDebugSymbols();
+ if(m_module->GetNumCompileUnits())
+ {
+ strm.Indent("Debug info loaded.");
+ }
+ else
+ {
+ strm.Indent("Debug info does not exist.");
+ }
+ strm.EOL();
+ strm.IndentMore();
+ strm.Indent();
+ strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size()));
+ strm.EOL();
+ strm.IndentMore();
+ for (const auto &global : m_globals)
+ {
+ global.Dump(strm);
+ }
+ strm.IndentLess();
+ strm.Indent();
+ strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size()));
+ strm.EOL();
+ strm.IndentMore();
+ for (const auto &kernel : m_kernels)
+ {
+ kernel.Dump(strm);
+ }
+ strm.Printf("Pragmas: %" PRIu64 , static_cast<uint64_t>(m_pragmas.size()));
+ strm.EOL();
+ strm.IndentMore();
+ for (const auto &key_val : m_pragmas)
+ {
+ strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str());
+ strm.EOL();
+ }
+ strm.IndentLess(4);
+}
+
+void
+RSGlobalDescriptor::Dump(Stream &strm) const
+{
+ strm.Indent(m_name.AsCString());
+ VariableList var_list;
+ m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list);
+ if (var_list.GetSize() == 1)
+ {
+ auto var = var_list.GetVariableAtIndex(0);
+ auto type = var->GetType();
+ if(type)
+ {
+ strm.Printf(" - ");
+ type->DumpTypeName(&strm);
+ }
+ else
+ {
+ strm.Printf(" - Unknown Type");
+ }
+ }
+ else
+ {
+ strm.Printf(" - variable identified, but not found in binary");
+ const Symbol* s = m_module->m_module->FindFirstSymbolWithNameAndType(m_name, eSymbolTypeData);
+ if (s)
+ {
+ strm.Printf(" (symbol exists) ");
+ }
+ }
+
+ strm.EOL();
+}
+
+void
+RSKernelDescriptor::Dump(Stream &strm) const
+{
+ strm.Indent(m_name.AsCString());
+ strm.EOL();
+}
+
+class CommandObjectRenderScriptRuntimeModuleProbe : public CommandObjectParsed
+{
+ private:
+ public:
+ CommandObjectRenderScriptRuntimeModuleProbe(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "renderscript module probe",
+ "Initiates a Probe of all loaded modules for kernels and other renderscript objects.",
+ "renderscript module probe",
+ eCommandRequiresTarget | eCommandRequiresProcess | eCommandProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectRenderScriptRuntimeModuleProbe() {}
+
+ bool
+ DoExecute(Args &command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ RenderScriptRuntime *runtime =
+ (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
+ auto module_list = target->GetImages();
+ bool new_rs_details = runtime->ProbeModules(module_list);
+ if (new_rs_details)
+ {
+ result.AppendMessage("New renderscript modules added to runtime model.");
+ }
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+
+ result.AppendErrorWithFormat("'%s' takes no arguments", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+};
+
+class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed
+{
+ private:
+ public:
+ CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "renderscript module dump",
+ "Dumps renderscript specific information for all modules.", "renderscript module dump",
+ eCommandRequiresProcess | eCommandProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectRenderScriptRuntimeModuleDump() {}
+
+ bool
+ DoExecute(Args &command, CommandReturnObject &result)
+ {
+ RenderScriptRuntime *runtime =
+ (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
+ runtime->DumpModules(result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+};
+
+class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword
+{
+ private:
+ public:
+ CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(interpreter, "renderscript module", "Commands that deal with renderscript modules.",
+ NULL)
+ {
+ LoadSubCommand("probe", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleProbe(interpreter)));
+ LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(interpreter)));
+ }
+
+ ~CommandObjectRenderScriptRuntimeModule() {}
+};
+
+class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed
+{
+ private:
+ public:
+ CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "renderscript kernel list",
+ "Lists renderscript kernel names and associated script resources.", "renderscript kernel list",
+ eCommandRequiresProcess | eCommandProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectRenderScriptRuntimeKernelList() {}
+
+ bool
+ DoExecute(Args &command, CommandReturnObject &result)
+ {
+ RenderScriptRuntime *runtime =
+ (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
+ runtime->DumpKernels(result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+};
+
+class CommandObjectRenderScriptRuntimeKernelBreakpoint : public CommandObjectParsed
+{
+ private:
+ public:
+ CommandObjectRenderScriptRuntimeKernelBreakpoint(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "renderscript kernel breakpoint",
+ "Sets a breakpoint on a renderscript kernel.", "renderscript kernel breakpoint",
+ eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused)
+ {
+ }
+
+ ~CommandObjectRenderScriptRuntimeKernelBreakpoint() {}
+
+ bool
+ DoExecute(Args &command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 1)
+ {
+ RenderScriptRuntime *runtime =
+ (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
+
+ Error error;
+ runtime->AttemptBreakpointAtKernelName(result.GetOutputStream(), command.GetArgumentAtIndex(0), error);
+
+ if (error.Success())
+ {
+ result.AppendMessage("Breakpoint(s) created");
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ result.SetStatus(eReturnStatusFailed);
+ result.AppendErrorWithFormat("Error: %s", error.AsCString());
+ return false;
+ }
+
+ result.AppendErrorWithFormat("'%s' takes 1 argument of kernel name", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+};
+
+class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword
+{
+ private:
+ public:
+ CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(interpreter, "renderscript kernel", "Commands that deal with renderscript kernels.",
+ NULL)
+ {
+ LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(interpreter)));
+ LoadSubCommand("breakpoint", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter)));
+ }
+
+ ~CommandObjectRenderScriptRuntimeKernel() {}
+};
+
+class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed
+{
+ private:
+ public:
+ CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "renderscript context dump",
+ "Dumps renderscript context information.", "renderscript context dump",
+ eCommandRequiresProcess | eCommandProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectRenderScriptRuntimeContextDump() {}
+
+ bool
+ DoExecute(Args &command, CommandReturnObject &result)
+ {
+ RenderScriptRuntime *runtime =
+ (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
+ runtime->DumpContexts(result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+};
+
+class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword
+{
+ private:
+ public:
+ CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(interpreter, "renderscript context", "Commands that deal with renderscript contexts.",
+ NULL)
+ {
+ LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(interpreter)));
+ }
+
+ ~CommandObjectRenderScriptRuntimeContext() {}
+};
+
+class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed
+{
+ private:
+ public:
+ CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "renderscript status",
+ "Displays current renderscript runtime status.", "renderscript status",
+ eCommandRequiresProcess | eCommandProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectRenderScriptRuntimeStatus() {}
+
+ bool
+ DoExecute(Args &command, CommandReturnObject &result)
+ {
+ RenderScriptRuntime *runtime =
+ (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
+ runtime->Status(result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+};
+
+class CommandObjectRenderScriptRuntime : public CommandObjectMultiword
+{
+ public:
+ CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(interpreter, "renderscript", "A set of commands for operating on renderscript.",
+ "renderscript <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand("module", CommandObjectSP(new CommandObjectRenderScriptRuntimeModule(interpreter)));
+ LoadSubCommand("status", CommandObjectSP(new CommandObjectRenderScriptRuntimeStatus(interpreter)));
+ LoadSubCommand("kernel", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernel(interpreter)));
+ LoadSubCommand("context", CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(interpreter)));
+ }
+
+ ~CommandObjectRenderScriptRuntime() {}
+};
+
+void
+RenderScriptRuntime::Initiate()
+{
+ assert(!m_initiated);
+}
+
+RenderScriptRuntime::RenderScriptRuntime(Process *process)
+ : lldb_private::CPPLanguageRuntime(process), m_initiated(false), m_debuggerPresentFlagged(false)
+{
+ ModulesDidLoad(process->GetTarget().GetImages());
+}
+
+lldb::CommandObjectSP
+RenderScriptRuntime::GetCommandObject(lldb_private::CommandInterpreter& interpreter)
+{
+ static CommandObjectSP command_object;
+ if(!command_object)
+ {
+ command_object.reset(new CommandObjectRenderScriptRuntime(interpreter));
+ }
+ return command_object;
+}
+
diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h
new file mode 100644
index 000000000000..2a01e744e976
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h
@@ -0,0 +1,232 @@
+//===-- RenderScriptRuntime.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_RenderScriptRuntime_h_
+#define liblldb_RenderScriptRuntime_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+#include "lldb/Core/Module.h"
+
+namespace lldb_private
+{
+
+typedef uint32_t RSSlot;
+class RSModuleDescriptor;
+struct RSGlobalDescriptor;
+struct RSKernelDescriptor;
+
+typedef std::shared_ptr<RSModuleDescriptor> RSModuleDescriptorSP;
+typedef std::shared_ptr<RSGlobalDescriptor> RSGlobalDescriptorSP;
+typedef std::shared_ptr<RSKernelDescriptor> RSKernelDescriptorSP;
+
+
+
+struct RSKernelDescriptor
+{
+ public:
+ RSKernelDescriptor(const RSModuleDescriptor *module, const char *name, uint32_t slot)
+ : m_module(module)
+ , m_name(name)
+ , m_slot(slot)
+ {
+ }
+
+ void Dump(Stream &strm) const;
+
+ const RSModuleDescriptor *m_module;
+ ConstString m_name;
+ RSSlot m_slot;
+};
+
+struct RSGlobalDescriptor
+{
+ public:
+ RSGlobalDescriptor(const RSModuleDescriptor *module, const char *name )
+ : m_module(module)
+ , m_name(name)
+ {
+ }
+
+ void Dump(Stream &strm) const;
+
+ const RSModuleDescriptor *m_module;
+ ConstString m_name;
+};
+
+class RSModuleDescriptor
+{
+ public:
+ RSModuleDescriptor(const lldb::ModuleSP &module)
+ : m_module(module)
+ {
+ }
+
+ ~RSModuleDescriptor() {}
+
+ bool ParseRSInfo();
+
+ void Dump(Stream &strm) const;
+
+ const lldb::ModuleSP m_module;
+ std::vector<RSKernelDescriptor> m_kernels;
+ std::vector<RSGlobalDescriptor> m_globals;
+ std::map<std::string, std::string> m_pragmas;
+ std::string m_resname;
+};
+
+class RenderScriptRuntime : public lldb_private::CPPLanguageRuntime
+{
+ public:
+
+ enum ModuleKind
+ {
+ eModuleKindIgnored,
+ eModuleKindLibRS,
+ eModuleKindDriver,
+ eModuleKindImpl,
+ eModuleKindKernelObj
+ };
+
+
+ ~RenderScriptRuntime() {}
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void Initialize();
+
+ static void Terminate();
+
+ static lldb_private::LanguageRuntime *CreateInstance(Process *process, lldb::LanguageType language);
+
+ static lldb::CommandObjectSP GetCommandObject(CommandInterpreter& interpreter);
+
+ static lldb_private::ConstString GetPluginNameStatic();
+
+ static bool IsRenderScriptModule(const lldb::ModuleSP &module_sp);
+
+ static ModuleKind GetModuleKind(const lldb::ModuleSP &module_sp);
+
+ static void ModulesDidLoad(const lldb::ProcessSP& process_sp, const ModuleList &module_list );
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString GetPluginName();
+
+ virtual uint32_t GetPluginVersion();
+
+ virtual bool IsVTableName(const char *name);
+
+ virtual bool GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic,
+ TypeAndOrName &class_type_or_name, Address &address);
+
+ virtual bool CouldHaveDynamicValue(ValueObject &in_value);
+
+ virtual lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp);
+
+ bool LoadModule(const lldb::ModuleSP &module_sp);
+
+ bool ProbeModules(const ModuleList module_list);
+
+ void DumpModules(Stream &strm) const;
+
+ void DumpContexts(Stream &strm) const;
+
+ void DumpKernels(Stream &strm) const;
+
+ void AttemptBreakpointAtKernelName(Stream &strm, const char *name, Error &error);
+
+ void Status(Stream &strm) const;
+
+ virtual size_t GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates) {
+ return static_cast<size_t>(0);
+ }
+
+ virtual void ModulesDidLoad(const ModuleList &module_list );
+
+ void Update();
+
+ void Initiate();
+
+ protected:
+
+ void FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp);
+
+ void LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind);
+
+ struct RuntimeHook;
+ typedef void (RenderScriptRuntime::*CaptureStateFn)(RuntimeHook* hook_info, ExecutionContext &context); // Please do this!
+
+ struct HookDefn
+ {
+ const char * name;
+ const char * symbol_name;
+ uint32_t version;
+ ModuleKind kind;
+ CaptureStateFn grabber;
+ };
+
+ struct RuntimeHook
+ {
+ lldb::addr_t address;
+ const HookDefn *defn;
+ lldb::BreakpointSP bp_sp;
+ };
+
+ typedef std::shared_ptr<RuntimeHook> RuntimeHookSP;
+
+ struct ScriptDetails
+ {
+ std::string resname;
+ std::string scriptDyLib;
+ std::string cachedir;
+ lldb::addr_t context;
+ lldb::addr_t script;
+ };
+
+ lldb::ModuleSP m_libRS;
+ lldb::ModuleSP m_libRSDriver;
+ lldb::ModuleSP m_libRSCpuRef;
+ std::vector<RSModuleDescriptorSP> m_rsmodules;
+ std::vector<ScriptDetails> m_scripts;
+
+ std::map<lldb::addr_t, RSModuleDescriptorSP> m_scriptMappings;
+ std::map<lldb::addr_t, RuntimeHookSP> m_runtimeHooks;
+
+ bool m_initiated;
+ bool m_debuggerPresentFlagged;
+ static const HookDefn s_runtimeHookDefns[];
+ static const size_t s_runtimeHookCount;
+
+ private:
+ RenderScriptRuntime(Process *process); // Call CreateInstance instead.
+
+ static bool HookCallback(void *baton, StoppointCallbackContext *ctx, lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ void HookCallback(RuntimeHook* hook_info, ExecutionContext& context);
+
+ bool GetArg32Simple(ExecutionContext& context, uint32_t arg, uint32_t *data);
+
+ void CaptureScriptInit1(RuntimeHook* hook_info, ExecutionContext& context);
+ void CaptureAllocationInit1(RuntimeHook* hook_info, ExecutionContext& context);
+ void CaptureSetGlobalVar1(RuntimeHook* hook_info, ExecutionContext& context);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_RenderScriptRuntime_h_
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
index 1e2a0c721ff6..8209d23c0aee 100644
--- a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
+++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -364,7 +364,7 @@ ObjectContainerBSDArchive::CreateInstance
// 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
- DataBufferSP archive_data_sp (file->MemoryMapFileContents(file_offset, length));
+ DataBufferSP archive_data_sp (file->MemoryMapFileContentsIfLocal(file_offset, length));
lldb::offset_t archive_data_offset = 0;
Archive::shared_ptr archive_sp (Archive::FindCachedArchive (*file,
@@ -570,7 +570,7 @@ ObjectContainerBSDArchive::GetModuleSpecifications (const lldb_private::FileSpec
if (!archive_sp)
{
set_archive_arch = true;
- DataBufferSP data_sp (file.MemoryMapFileContents(file_offset, file_size));
+ DataBufferSP data_sp (file.MemoryMapFileContentsIfLocal(file_offset, file_size));
data.SetData (data_sp, 0, data_sp->GetByteSize());
archive_sp = Archive::ParseAndCacheArchiveForFile(file, ArchSpec(), file_mod_time, file_offset, data);
}
@@ -595,7 +595,8 @@ ObjectContainerBSDArchive::GetModuleSpecifications (const lldb_private::FileSpec
TimeValue object_mod_time;
object_mod_time.OffsetWithSeconds(object->ar_date);
spec.GetObjectName () = object->ar_name;
- spec.SetObjectOffset(object_file_offset);
+ spec.SetObjectOffset (object_file_offset);
+ spec.SetObjectSize (file_size - object_file_offset);
spec.GetObjectModificationTime () = object_mod_time;
}
}
diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
index 12392c24407b..641a7cc3e0e2 100644
--- a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
+++ b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
@@ -180,7 +180,7 @@ ELFHeader::GetRelocationJumpSlotType() const
slot = R_PPC64_JMP_SLOT;
break;
case EM_386:
- case EM_486:
+ case EM_IAMCU: // FIXME: is this correct?
slot = R_386_JUMP_SLOT;
break;
case EM_X86_64:
@@ -278,9 +278,8 @@ ELFSymbol::typeToCString(unsigned char type)
ENUM_TO_CSTR(STT_FILE);
ENUM_TO_CSTR(STT_COMMON);
ENUM_TO_CSTR(STT_TLS);
- ENUM_TO_CSTR(STT_LOOS);
- ENUM_TO_CSTR(STT_HIOS);
ENUM_TO_CSTR(STT_GNU_IFUNC);
+ ENUM_TO_CSTR(STT_HIOS);
ENUM_TO_CSTR(STT_LOPROC);
ENUM_TO_CSTR(STT_HIPROC);
}
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index e7bf20e18008..f9cec2415382 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -27,7 +27,6 @@
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
-#include "lldb/Host/HostInfo.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringRef.h"
@@ -48,6 +47,7 @@ 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";
+const char *const LLDB_NT_OWNER_ANDROID = "Android";
// ELF note type definitions
const elf_word LLDB_NT_FREEBSD_ABI_TAG = 0x01;
@@ -283,8 +283,39 @@ kalimbaVariantFromElfFlags(const elf::elf_word e_flags)
}
static uint32_t
+mipsVariantFromElfFlags(const elf::elf_word e_flags, uint32_t endian)
+{
+ const uint32_t mips_arch = e_flags & llvm::ELF::EF_MIPS_ARCH;
+ uint32_t arch_variant = ArchSpec::eMIPSSubType_unknown;
+
+ switch (mips_arch)
+ {
+ case llvm::ELF::EF_MIPS_ARCH_32:
+ return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32el : ArchSpec::eMIPSSubType_mips32;
+ case llvm::ELF::EF_MIPS_ARCH_32R2:
+ return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32r2el : ArchSpec::eMIPSSubType_mips32r2;
+ case llvm::ELF::EF_MIPS_ARCH_32R6:
+ return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32r6el : ArchSpec::eMIPSSubType_mips32r6;
+ case llvm::ELF::EF_MIPS_ARCH_64:
+ return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64el : ArchSpec::eMIPSSubType_mips64;
+ case llvm::ELF::EF_MIPS_ARCH_64R2:
+ return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64r2el : ArchSpec::eMIPSSubType_mips64r2;
+ case llvm::ELF::EF_MIPS_ARCH_64R6:
+ return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64r6el : ArchSpec::eMIPSSubType_mips64r6;
+ default:
+ break;
+ }
+
+ return arch_variant;
+}
+
+static uint32_t
subTypeFromElfHeader(const elf::ELFHeader& header)
{
+ if (header.e_machine == llvm::ELF::EM_MIPS)
+ return mipsVariantFromElfFlags (header.e_flags,
+ header.e_ident[EI_DATA]);
+
return
llvm::ELF::EM_CSR_KALIMBA == header.e_machine ?
kalimbaVariantFromElfFlags(header.e_flags) :
@@ -365,7 +396,7 @@ ObjectFileELF::CreateInstance (const lldb::ModuleSP &module_sp,
{
if (!data_sp)
{
- data_sp = file->MemoryMapFileContents(file_offset, length);
+ data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
data_offset = 0;
}
@@ -376,7 +407,7 @@ ObjectFileELF::CreateInstance (const lldb::ModuleSP &module_sp,
{
// Update the data to contain the entire file if it doesn't already
if (data_sp->GetByteSize() < length) {
- data_sp = file->MemoryMapFileContents(file_offset, length);
+ data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
data_offset = 0;
magic = data_sp->GetBytes();
}
@@ -566,6 +597,12 @@ OSABIAsCString (unsigned char osabi_byte)
#undef _MAKE_OSABI_CASE
}
+//
+// WARNING : This function is being deprecated
+// It's functionality has moved to ArchSpec::SetArchitecture
+// This function is only being kept to validate the move.
+//
+// TODO : Remove this function
static bool
GetOsFromOSABI (unsigned char osabi_byte, llvm::Triple::OSType &ostype)
{
@@ -604,29 +641,33 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
{
if (data_sp)
{
- ModuleSpec spec;
- spec.GetFileSpec() = file;
+ ModuleSpec spec (file);
const uint32_t sub_type = subTypeFromElfHeader(header);
spec.GetArchitecture().SetArchitecture(eArchTypeELF,
header.e_machine,
- sub_type);
+ sub_type,
+ header.e_ident[EI_OSABI]);
if (spec.GetArchitecture().IsValid())
{
llvm::Triple::OSType ostype;
- // First try to determine the OS type from the OSABI field in the elf header.
+ llvm::Triple::VendorType vendor;
+ llvm::Triple::OSType spec_ostype = spec.GetArchitecture ().GetTriple ().getOS ();
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);
+ // SetArchitecture should have set the vendor to unknown
+ vendor = spec.GetArchitecture ().GetTriple ().getVendor ();
+ assert(vendor == llvm::Triple::UnknownVendor);
+ //
+ // Validate it is ok to remove GetOsFromOSABI
+ GetOsFromOSABI (header.e_ident[EI_OSABI], ostype);
+ assert(spec_ostype == ostype);
+ if (spec_ostype != llvm::Triple::OSType::UnknownOS)
+ {
if (log)
log->Printf ("ObjectFileELF::%s file '%s' set ELF module OS type from ELF header OSABI.", __FUNCTION__, file.GetPath ().c_str ());
}
@@ -636,7 +677,7 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
size_t section_header_end = header.e_shoff + header.e_shnum * header.e_shentsize;
if (section_header_end > data_sp->GetByteSize())
{
- data_sp = file.MemoryMapFileContents (file_offset, section_header_end);
+ data_sp = file.MemoryMapFileContentsIfLocal (file_offset, section_header_end);
data.SetData(data_sp);
}
@@ -647,14 +688,7 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
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 ());
@@ -678,7 +712,7 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
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_sp = file.MemoryMapFileContentsIfLocal(file_offset, program_headers_end);
data.SetData(data_sp);
}
ProgramHeaderColl program_headers;
@@ -693,7 +727,7 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
if (segment_data_end > data_sp->GetByteSize())
{
- data_sp = file.MemoryMapFileContents(file_offset, segment_data_end);
+ data_sp = file.MemoryMapFileContentsIfLocal(file_offset, segment_data_end);
data.SetData(data_sp);
}
@@ -702,7 +736,7 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
else
{
// Need to map entire file into memory to calculate the crc.
- data_sp = file.MemoryMapFileContents (file_offset, SIZE_MAX);
+ data_sp = file.MemoryMapFileContentsIfLocal (file_offset, SIZE_MAX);
data.SetData(data_sp);
gnu_debuglink_crc = calc_gnu_debuglink_crc32 (data.GetDataStart(), data.GetByteSize());
}
@@ -773,10 +807,10 @@ ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp,
}
ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp,
- DataBufferSP& data_sp,
+ DataBufferSP& header_data_sp,
const lldb::ProcessSP &process_sp,
addr_t header_addr) :
- ObjectFile(module_sp, process_sp, LLDB_INVALID_ADDRESS, data_sp),
+ ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
m_header(),
m_uuid(),
m_gnu_debuglink_file(),
@@ -826,7 +860,14 @@ ObjectFileELF::SetLoadAddress (Target &target,
// if (section_sp && !section_sp->IsThreadSpecific())
if (section_sp && section_sp->Test(SHF_ALLOC))
{
- if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value))
+ lldb::addr_t load_addr = section_sp->GetFileAddress() + value;
+
+ // On 32-bit systems the load address have to fit into 4 bytes. The rest of
+ // the bytes are the overflow from the addition.
+ if (GetAddressByteSize() == 4)
+ load_addr &= 0xFFFFFFFF;
+
+ if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, load_addr))
++num_loaded_sections;
}
}
@@ -869,25 +910,18 @@ ObjectFileELF::GetAddressClass (addr_t file_addr)
if (res != eAddressClassCode)
return res;
- ArchSpec arch_spec;
- GetArchitecture(arch_spec);
- if (arch_spec.GetMachine() != llvm::Triple::arm)
- return res;
-
- auto symtab = GetSymtab();
- if (symtab == nullptr)
- return res;
-
- auto symbol = symtab->FindSymbolContainingFileAddress(file_addr);
- if (symbol == nullptr)
- return res;
+ auto ub = m_address_class_map.upper_bound(file_addr);
+ if (ub == m_address_class_map.begin())
+ {
+ // No entry in the address class map before the address. Return
+ // default address class for an address in a code section.
+ return eAddressClassCode;
+ }
- // Thumb symbols have the lower bit set in the flags field so we just check
- // for that.
- if (symbol->GetFlags() & ARM_ELF_SYM_IS_THUMB)
- res = eAddressClassCodeAlternateISA;
+ // Move iterator to the address class entry preceding address
+ --ub;
- return res;
+ return ub->second;
}
size_t
@@ -906,7 +940,28 @@ bool
ObjectFileELF::ParseHeader()
{
lldb::offset_t offset = 0;
- return m_header.Parse(m_data, &offset);
+ if (!m_header.Parse(m_data, &offset))
+ return false;
+
+ if (!IsInMemory())
+ return true;
+
+ // For in memory object files m_data might not contain the full object file. Try to load it
+ // until the end of the "Section header table" what is at the end of the ELF file.
+ addr_t file_size = m_header.e_shoff + m_header.e_shnum * m_header.e_shentsize;
+ if (m_data.GetByteSize() < file_size)
+ {
+ ProcessSP process_sp (m_process_wp.lock());
+ if (!process_sp)
+ return false;
+
+ DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size);
+ if (!data_sp)
+ return false;
+ m_data.SetData(data_sp, 0, file_size);
+ }
+
+ return true;
}
bool
@@ -1337,6 +1392,11 @@ ObjectFileELF::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, l
(void)cstr;
}
}
+ else if (note.n_name == LLDB_NT_OWNER_ANDROID)
+ {
+ arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux);
+ arch_spec.GetTriple().setEnvironment(llvm::Triple::EnvironmentType::Android);
+ }
if (!processed)
offset += llvm::RoundUpToAlignment(note.n_descsz, 4);
@@ -1366,32 +1426,15 @@ ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
// We'll refine this with note data as we parse the notes.
if (arch_spec.GetTriple ().getOS () == llvm::Triple::OSType::UnknownOS)
{
+ llvm::Triple::OSType ostype;
+ llvm::Triple::OSType spec_ostype;
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;
- }
+ arch_spec.SetArchitecture (eArchTypeELF, header.e_machine, sub_type, header.e_ident[EI_OSABI]);
+ //
+ // Validate if it is ok to remove GetOsFromOSABI
+ GetOsFromOSABI (header.e_ident[EI_OSABI], ostype);
+ spec_ostype = arch_spec.GetTriple ().getOS ();
+ assert(spec_ostype == ostype);
}
// If there are no section headers we are done.
@@ -1453,7 +1496,15 @@ ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
}
// Process ELF note section entries.
- if (header.sh_type == SHT_NOTE)
+ bool is_note_header = (header.sh_type == SHT_NOTE);
+
+ // The section header ".note.android.ident" is stored as a
+ // PROGBITS type header but it is actually a note header.
+ static ConstString g_sect_name_android_ident (".note.android.ident");
+ if (!is_note_header && name == g_sect_name_android_ident)
+ is_note_header = true;
+
+ if (is_note_header)
{
// Allow notes to refine module info.
DataExtractor data;
@@ -1504,6 +1555,13 @@ ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id)
return DataExtractor(m_data, segment_header->p_offset, segment_header->p_filesz);
}
+std::string
+ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const
+{
+ size_t pos = symbol_name.find("@");
+ return symbol_name.substr(0, pos).str();
+}
+
//----------------------------------------------------------------------
// ParseSectionHeaders
//----------------------------------------------------------------------
@@ -1525,6 +1583,17 @@ ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id)
return NULL;
}
+lldb::user_id_t
+ObjectFileELF::GetSectionIndexByName(const char* name)
+{
+ if (!name || !name[0] || !ParseSectionHeaders())
+ return 0;
+ for (size_t i = 1; i < m_section_headers.size(); ++i)
+ if (m_section_headers[i].section_name == ConstString(name))
+ return i;
+ return 0;
+}
+
void
ObjectFileELF::CreateSections(SectionList &unified_section_list)
{
@@ -1826,45 +1895,92 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
}
}
- ArchSpec arch;
int64_t symbol_value_offset = 0;
uint32_t additional_flags = 0;
- if (GetArchitecture(arch) &&
- arch.GetMachine() == llvm::Triple::arm)
+ ArchSpec arch;
+ if (GetArchitecture(arch))
{
- // ELF symbol tables may contain some mapping symbols. They provide
- // information about the underlying data. There are three of them
- // currently defined:
- // $a[.<any>]* - marks an ARM instruction sequence
- // $t[.<any>]* - marks a THUMB instruction sequence
- // $d[.<any>]* - marks a data item sequence (e.g. lit pool)
- // These symbols interfere with normal debugger operations and we
- // don't need them. We can drop them here.
-
- static const llvm::StringRef g_armelf_arm_marker("$a");
- static const llvm::StringRef g_armelf_thumb_marker("$t");
- static const llvm::StringRef g_armelf_data_marker("$d");
- llvm::StringRef symbol_name_ref(symbol_name);
-
- if (symbol_name &&
- (symbol_name_ref.startswith(g_armelf_arm_marker) ||
- symbol_name_ref.startswith(g_armelf_thumb_marker) ||
- symbol_name_ref.startswith(g_armelf_data_marker)))
- continue;
+ if (arch.GetMachine() == llvm::Triple::arm)
+ {
+ if (symbol.getBinding() == STB_LOCAL && symbol_name && symbol_name[0] == '$')
+ {
+ // These are reserved for the specification (e.g.: mapping
+ // symbols). We don't want to add them to the symbol table.
- // THUMB functions have the lower bit of their address set. Fixup
- // the actual address and mark the symbol as THUMB.
- if (symbol_type == eSymbolTypeCode && symbol.st_value & 1)
+ if (symbol_type == eSymbolTypeCode)
+ {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ if (symbol_name_ref == "$a" || symbol_name_ref.startswith("$a."))
+ {
+ // $a[.<any>]* - marks an ARM instruction sequence
+ m_address_class_map[symbol.st_value] = eAddressClassCode;
+ }
+ else if (symbol_name_ref == "$b" || symbol_name_ref.startswith("$b.") ||
+ symbol_name_ref == "$t" || symbol_name_ref.startswith("$t."))
+ {
+ // $b[.<any>]* - marks a THUMB BL instruction sequence
+ // $t[.<any>]* - marks a THUMB instruction sequence
+ m_address_class_map[symbol.st_value] = eAddressClassCodeAlternateISA;
+ }
+ else if (symbol_name_ref == "$d" || symbol_name_ref.startswith("$d."))
+ {
+ // $d[.<any>]* - marks a data item sequence (e.g. lit pool)
+ m_address_class_map[symbol.st_value] = eAddressClassData;
+ }
+ }
+
+ continue;
+ }
+ }
+ else if (arch.GetMachine() == llvm::Triple::aarch64)
{
- // Substracting 1 from the address effectively unsets
- // the low order bit, which results in the address
- // actually pointing to the beginning of the symbol.
- // This delta will be used below in conjuction with
- // symbol.st_value to produce the final symbol_value
- // that we store in the symtab.
- symbol_value_offset = -1;
- additional_flags = ARM_ELF_SYM_IS_THUMB;
+ if (symbol.getBinding() == STB_LOCAL && symbol_name && symbol_name[0] == '$')
+ {
+ // These are reserved for the specification (e.g.: mapping
+ // symbols). We don't want to add them to the symbol table.
+
+ if (symbol_type == eSymbolTypeCode)
+ {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ if (symbol_name_ref == "$x" || symbol_name_ref.startswith("$x."))
+ {
+ // $x[.<any>]* - marks an A64 instruction sequence
+ m_address_class_map[symbol.st_value] = eAddressClassCode;
+ }
+ else if (symbol_name_ref == "$d" || symbol_name_ref.startswith("$d."))
+ {
+ // $d[.<any>]* - marks a data item sequence (e.g. lit pool)
+ m_address_class_map[symbol.st_value] = eAddressClassData;
+ }
+ }
+
+ continue;
+ }
+ }
+
+ if (arch.GetMachine() == llvm::Triple::arm)
+ {
+ if (symbol_type == eSymbolTypeCode)
+ {
+ if (symbol.st_value & 1)
+ {
+ // Subtracting 1 from the address effectively unsets
+ // the low order bit, which results in the address
+ // actually pointing to the beginning of the symbol.
+ // This delta will be used below in conjunction with
+ // symbol.st_value to produce the final symbol_value
+ // that we store in the symtab.
+ symbol_value_offset = -1;
+ additional_flags = ARM_ELF_SYM_IS_THUMB;
+ m_address_class_map[symbol.st_value^1] = eAddressClassCodeAlternateISA;
+ }
+ else
+ {
+ // This address is ARM
+ m_address_class_map[symbol.st_value] = eAddressClassCode;
+ }
+ }
}
}
@@ -1890,30 +2006,53 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
// symbol_value_offset may contain 0 for ARM symbols or -1 for
// THUMB symbols. See above for more details.
- uint64_t symbol_value = symbol.st_value | symbol_value_offset;
+ uint64_t symbol_value = symbol.st_value + symbol_value_offset;
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 | additional_flags;
bool is_mangled = symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false;
+ llvm::StringRef symbol_ref(symbol_name);
+
+ // Symbol names may contain @VERSION suffixes. Find those and strip them temporarily.
+ size_t version_pos = symbol_ref.find('@');
+ bool has_suffix = version_pos != llvm::StringRef::npos;
+ llvm::StringRef symbol_bare = symbol_ref.substr(0, version_pos);
+ Mangled mangled(ConstString(symbol_bare), is_mangled);
+
+ // Now append the suffix back to mangled and unmangled names. Only do it if the
+ // demangling was sucessful (string is not empty).
+ if (has_suffix)
+ {
+ llvm::StringRef suffix = symbol_ref.substr(version_pos);
+
+ llvm::StringRef mangled_name = mangled.GetMangledName().GetStringRef();
+ if (! mangled_name.empty())
+ mangled.SetMangledName( ConstString((mangled_name + suffix).str()) );
+
+ llvm::StringRef demangled_name = mangled.GetDemangledName().GetStringRef();
+ if (! demangled_name.empty())
+ mangled.SetDemangledName( ConstString((demangled_name + suffix).str()) );
+ }
+
Symbol dc_symbol(
i + start_id, // ID is the original symbol table index.
- symbol_name, // Symbol name.
- is_mangled, // Is the symbol name mangled?
+ mangled,
symbol_type, // Type of this symbol
is_global, // Is this globally visible?
false, // Is this symbol debug info?
false, // Is this symbol a trampoline?
false, // Is this symbol artificial?
- symbol_section_sp, // Section in which this symbol is defined or null.
- symbol_value, // Offset in section or symbol value.
- symbol.st_size, // Size in bytes of this symbol.
- true, // Size is valid
- flags); // Symbol flags.
+ AddressRange(
+ symbol_section_sp, // Section in which this symbol is defined or null.
+ symbol_value, // Offset in section or symbol value.
+ symbol.st_size), // Size in bytes of this symbol.
+ symbol.st_size != 0, // Size is valid if it is not 0
+ has_suffix, // Contains linker annotations?
+ flags); // Symbol flags.
symtab->AddSymbol(dc_symbol);
}
-
return i;
}
@@ -2033,6 +2172,36 @@ ObjectFileELF::PLTRelocationType()
return 0;
}
+// Returns the size of the normal plt entries and the offset of the first normal plt entry. The
+// 0th entry in the plt table is ususally a resolution entry which have different size in some
+// architectures then the rest of the plt entries.
+static std::pair<uint64_t, uint64_t>
+GetPltEntrySizeAndOffset(const ELFSectionHeader* rel_hdr, const ELFSectionHeader* plt_hdr)
+{
+ const elf_xword num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize;
+
+ // Clang 3.3 sets entsize to 4 for 32-bit binaries, but the plt entries are 16 bytes.
+ // So round the entsize up by the alignment if addralign is set.
+ elf_xword plt_entsize = plt_hdr->sh_addralign ?
+ llvm::RoundUpToAlignment (plt_hdr->sh_entsize, plt_hdr->sh_addralign) : plt_hdr->sh_entsize;
+
+ if (plt_entsize == 0)
+ {
+ // The linker haven't set the plt_hdr->sh_entsize field. Try to guess the size of the plt
+ // entries based on the number of entries and the size of the plt section with the
+ // asumption that the size of the 0th entry is at least as big as the size of the normal
+ // entries and it isn't mutch bigger then that.
+ if (plt_hdr->sh_addralign)
+ plt_entsize = plt_hdr->sh_size / plt_hdr->sh_addralign / (num_relocations + 1) * plt_hdr->sh_addralign;
+ else
+ plt_entsize = plt_hdr->sh_size / (num_relocations + 1);
+ }
+
+ elf_xword plt_offset = plt_hdr->sh_size - num_relocations * plt_entsize;
+
+ return std::make_pair(plt_entsize, plt_offset);
+}
+
static unsigned
ParsePLTRelocations(Symtab *symbol_table,
user_id_t start_id,
@@ -2049,10 +2218,9 @@ ParsePLTRelocations(Symtab *symbol_table,
ELFRelocation rel(rel_type);
ELFSymbol symbol;
lldb::offset_t offset = 0;
- // Clang 3.3 sets entsize to 4 for 32-bit binaries, but the plt entries are 16 bytes.
- // So round the entsize up by the alignment if addralign is set.
- const elf_xword plt_entsize = plt_hdr->sh_addralign ?
- llvm::RoundUpToAlignment (plt_hdr->sh_entsize, plt_hdr->sh_addralign) : plt_hdr->sh_entsize;
+
+ uint64_t plt_offset, plt_entsize;
+ std::tie(plt_entsize, plt_offset) = GetPltEntrySizeAndOffset(rel_hdr, plt_hdr);
const elf_xword num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize;
typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel);
@@ -2081,13 +2249,12 @@ ParsePLTRelocations(Symtab *symbol_table,
continue;
lldb::offset_t symbol_offset = reloc_symbol(rel) * sym_hdr->sh_entsize;
- uint64_t plt_index = (i + 1) * plt_entsize;
-
if (!symbol.Parse(symtab_data, &symbol_offset))
break;
const char *symbol_name = strtab_data.PeekCStr(symbol.st_name);
bool is_mangled = symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false;
+ uint64_t plt_index = plt_offset + i * plt_entsize;
Symbol jump_symbol(
i + start_id, // Symbol table index
@@ -2102,6 +2269,7 @@ ParsePLTRelocations(Symtab *symbol_table,
plt_index, // Offset in section or symbol value.
plt_entsize, // Size in bytes of this symbol.
true, // Size is valid
+ false, // Contains linker annotations?
0); // Symbol flags.
symbol_table->AddSymbol(jump_symbol);
@@ -2123,6 +2291,13 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table,
user_id_t symtab_id = rel_hdr->sh_link;
user_id_t plt_id = rel_hdr->sh_info;
+ // If the link field doesn't point to the appropriate symbol name table then
+ // try to find it by name as some compiler don't fill in the link fields.
+ if (!symtab_id)
+ symtab_id = GetSectionIndexByName(".dynsym");
+ if (!plt_id)
+ plt_id = GetSectionIndexByName(".plt");
+
if (!symtab_id || !plt_id)
return 0;
@@ -2234,7 +2409,7 @@ ObjectFileELF::RelocateSection(Symtab* symtab, const ELFHeader *hdr, const ELFSe
symbol = symtab->FindSymbolByID(reloc_symbol(rel));
if (symbol)
{
- addr_t value = symbol->GetAddress().GetFileAddress();
+ addr_t value = symbol->GetAddressRef().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);
@@ -2247,7 +2422,7 @@ ObjectFileELF::RelocateSection(Symtab* symtab, const ELFHeader *hdr, const ELFSe
symbol = symtab->FindSymbolByID(reloc_symbol(rel));
if (symbol)
{
- addr_t value = symbol->GetAddress().GetFileAddress();
+ addr_t value = symbol->GetAddressRef().GetFileAddress();
value += ELFRelocation::RelocAddend32(rel);
assert((reloc_type(rel) == R_X86_64_32 && (value <= UINT32_MAX)) ||
(reloc_type(rel) == R_X86_64_32S &&
@@ -2333,7 +2508,7 @@ ObjectFileELF::GetSymtab()
if (m_symtab_ap.get() == NULL)
{
- SectionList *section_list = GetSectionList();
+ SectionList *section_list = module_sp->GetSectionList();
if (!section_list)
return NULL;
@@ -2379,6 +2554,7 @@ ObjectFileELF::GetSymtab()
ParseTrampolineSymbols (m_symtab_ap.get(), symbol_id, reloc_header, reloc_id);
}
}
+ m_symtab_ap->CalculateSymbolSizes();
}
for (SectionHeaderCollIter I = m_section_headers.begin();
@@ -2443,6 +2619,7 @@ ObjectFileELF::ResolveSymbolForAddress(const Address& so_addr, bool verify_uniqu
offset, // Offset in section or symbol value.
range.GetByteSize(), // Size in bytes of this symbol.
true, // Size is valid.
+ false, // Contains linker annotations?
0); // Symbol flags.
if (symbol_id == m_symtab_ap->AddSymbol(eh_symbol))
return m_symtab_ap->SymbolAtIndex(symbol_id);
@@ -2631,22 +2808,22 @@ ObjectFileELF::DumpELFProgramHeader_p_flags(Stream *s, elf_word p_flags)
void
ObjectFileELF::DumpELFProgramHeaders(Stream *s)
{
- if (ParseProgramHeaders())
+ if (!ParseProgramHeaders())
+ return;
+
+ s->PutCString("Program Headers\n");
+ s->PutCString("IDX p_type p_offset p_vaddr p_paddr "
+ "p_filesz p_memsz p_flags p_align\n");
+ s->PutCString("==== --------------- -------- -------- -------- "
+ "-------- -------- ------------------------- --------\n");
+
+ uint32_t idx = 0;
+ for (ProgramHeaderCollConstIter I = m_program_headers.begin();
+ I != m_program_headers.end(); ++I, ++idx)
{
- s->PutCString("Program Headers\n");
- s->PutCString("IDX p_type p_offset p_vaddr p_paddr "
- "p_filesz p_memsz p_flags p_align\n");
- s->PutCString("==== --------------- -------- -------- -------- "
- "-------- -------- ------------------------- --------\n");
-
- uint32_t idx = 0;
- for (ProgramHeaderCollConstIter I = m_program_headers.begin();
- I != m_program_headers.end(); ++I, ++idx)
- {
- s->Printf("[%2u] ", idx);
- ObjectFileELF::DumpELFProgramHeader(s, *I);
- s->EOL();
- }
+ s->Printf("[%2u] ", idx);
+ ObjectFileELF::DumpELFProgramHeader(s, *I);
+ s->EOL();
}
}
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index b10dfb532cd0..99088d166b12 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -104,11 +104,11 @@ public:
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
- virtual lldb_private::ConstString
- GetPluginName();
+ lldb_private::ConstString
+ GetPluginName() override;
- virtual uint32_t
- GetPluginVersion();
+ uint32_t
+ GetPluginVersion() override;
//------------------------------------------------------------------
// ObjectFile Protocol.
@@ -116,64 +116,64 @@ public:
virtual
~ObjectFileELF();
- virtual bool
- ParseHeader();
+ bool
+ ParseHeader() override;
- virtual bool
+ bool
SetLoadAddress (lldb_private::Target &target,
lldb::addr_t value,
- bool value_is_offset);
+ bool value_is_offset) override;
- virtual lldb::ByteOrder
- GetByteOrder() const;
+ lldb::ByteOrder
+ GetByteOrder() const override;
- virtual bool
- IsExecutable () const;
+ bool
+ IsExecutable () const override;
- virtual uint32_t
- GetAddressByteSize() const;
+ uint32_t
+ GetAddressByteSize() const override;
- virtual lldb::AddressClass
- GetAddressClass (lldb::addr_t file_addr);
+ lldb::AddressClass
+ GetAddressClass (lldb::addr_t file_addr) override;
- virtual lldb_private::Symtab *
- GetSymtab();
+ lldb_private::Symtab *
+ GetSymtab() override;
- virtual lldb_private::Symbol *
- ResolveSymbolForAddress(const lldb_private::Address& so_addr, bool verify_unique);
+ lldb_private::Symbol *
+ ResolveSymbolForAddress(const lldb_private::Address& so_addr, bool verify_unique) override;
- virtual bool
- IsStripped ();
+ bool
+ IsStripped () override;
- virtual void
- CreateSections (lldb_private::SectionList &unified_section_list);
+ void
+ CreateSections (lldb_private::SectionList &unified_section_list) override;
- virtual void
- Dump(lldb_private::Stream *s);
+ void
+ Dump(lldb_private::Stream *s) override;
- virtual bool
- GetArchitecture (lldb_private::ArchSpec &arch);
+ bool
+ GetArchitecture (lldb_private::ArchSpec &arch) override;
- virtual bool
- GetUUID(lldb_private::UUID* uuid);
+ bool
+ GetUUID(lldb_private::UUID* uuid) override;
- virtual lldb_private::FileSpecList
- GetDebugSymbolFilePaths();
+ lldb_private::FileSpecList
+ GetDebugSymbolFilePaths() override;
- virtual uint32_t
- GetDependentModules(lldb_private::FileSpecList& files);
+ uint32_t
+ GetDependentModules(lldb_private::FileSpecList& files) override;
- virtual lldb_private::Address
- GetImageInfoAddress(lldb_private::Target *target);
+ lldb_private::Address
+ GetImageInfoAddress(lldb_private::Target *target) override;
- virtual lldb_private::Address
- GetEntryPointAddress ();
+ lldb_private::Address
+ GetEntryPointAddress () override;
- virtual ObjectFile::Type
- CalculateType();
+ ObjectFile::Type
+ CalculateType() override;
- virtual ObjectFile::Strata
- CalculateStrata();
+ ObjectFile::Strata
+ CalculateStrata() override;
// Returns number of program headers found in the ELF file.
size_t
@@ -187,6 +187,9 @@ public:
lldb_private::DataExtractor
GetSegmentDataByIndex(lldb::user_id_t id);
+ std::string
+ StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override;
+
private:
ObjectFileELF(const lldb::ModuleSP &module_sp,
lldb::DataBufferSP& data_sp,
@@ -196,7 +199,7 @@ private:
lldb::offset_t length);
ObjectFileELF (const lldb::ModuleSP &module_sp,
- lldb::DataBufferSP& data_sp,
+ lldb::DataBufferSP& header_data_sp,
const lldb::ProcessSP &process_sp,
lldb::addr_t header_addr);
@@ -216,6 +219,8 @@ private:
typedef DynamicSymbolColl::iterator DynamicSymbolCollIter;
typedef DynamicSymbolColl::const_iterator DynamicSymbolCollConstIter;
+ typedef std::map<lldb::addr_t, lldb::AddressClass> FileAddressToAddressClassMap;
+
/// 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;
@@ -249,6 +254,9 @@ private:
/// The architecture detected from parsing elf file contents.
lldb_private::ArchSpec m_arch_spec;
+ /// The address class for each symbol in the elf file
+ FileAddressToAddressClassMap m_address_class_map;
+
/// Returns a 1 based index of the given section header.
size_t
SectionIndex(const SectionHeaderCollIter &I);
diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp
index 5498bed13ebc..3103ed8fb8fe 100644
--- a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp
+++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp
@@ -11,7 +11,6 @@
#include "ObjectFileJIT.h"
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/DataBuffer.h"
#include "lldb/Core/DataBufferHeap.h"
diff --git a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
index 7ca337e797da..e744d13deec1 100644
--- a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
+++ b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#ifndef LLDB_DISABLE_PYTHON
#include "OperatingSystemPython.h"
@@ -22,9 +20,10 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Interpreter/CommandInterpreter.h"
-#include "lldb/Interpreter/PythonDataObjects.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Symbol/ClangNamespaceDecl.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/VariableList.h"
@@ -116,8 +115,9 @@ OperatingSystemPython::OperatingSystemPython (lldb_private::Process *process, co
os_plugin_class_name.erase (py_extension_pos);
// Add ".OperatingSystemPlugIn" to the module name to get a string like "modulename.OperatingSystemPlugIn"
os_plugin_class_name += ".OperatingSystemPlugIn";
- ScriptInterpreterObjectSP object_sp = m_interpreter->OSPlugin_CreatePluginObject(os_plugin_class_name.c_str(), process->CalculateProcess());
- if (object_sp && object_sp->GetObject())
+ StructuredData::ObjectSP object_sp =
+ m_interpreter->OSPlugin_CreatePluginObject(os_plugin_class_name.c_str(), process->CalculateProcess());
+ if (object_sp && object_sp->IsValid())
m_python_object_sp = object_sp;
}
}
@@ -139,12 +139,12 @@ OperatingSystemPython::GetDynamicRegisterInfo ()
if (log)
log->Printf ("OperatingSystemPython::GetDynamicRegisterInfo() fetching thread register definitions from python for pid %" PRIu64, m_process->GetID());
-
- PythonDictionary dictionary(m_interpreter->OSPlugin_RegisterInfo(m_python_object_sp));
+
+ StructuredData::DictionarySP dictionary = m_interpreter->OSPlugin_RegisterInfo(m_python_object_sp);
if (!dictionary)
return NULL;
-
- m_register_info_ap.reset (new DynamicRegisterInfo (dictionary, m_process->GetTarget().GetArchitecture().GetByteOrder()));
+
+ m_register_info_ap.reset(new DynamicRegisterInfo(*dictionary, m_process->GetTarget().GetArchitecture()));
assert (m_register_info_ap->GetNumRegisters() > 0);
assert (m_register_info_ap->GetNumRegisterSets() > 0);
}
@@ -176,11 +176,18 @@ OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list,
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OS));
- // First thing we have to do is get the API lock, and the run lock. We're going to change the thread
- // content of the process, and we're going to use python, which requires the API lock to do it.
- // So get & hold that. This is a recursive lock so we can grant it to any Python code called on the stack below us.
+ // First thing we have to do is to try to get the API lock, and the run lock.
+ // We're going to change the thread content of the process, and we're going
+ // to use python, which requires the API lock to do it.
+ //
+ // If someone already has the API lock, that is ok, we just want to avoid
+ // external code from making new API calls while this call is happening.
+ //
+ // This is a recursive lock so we can grant it to any Python code called on
+ // the stack below us.
Target &target = m_process->GetTarget();
- Mutex::Locker api_locker (target.GetAPIMutex());
+ Mutex::Locker api_locker;
+ api_locker.TryLock(target.GetAPIMutex());
if (log)
log->Printf ("OperatingSystemPython::UpdateThreadList() fetching thread data from python for pid %" PRIu64, m_process->GetID());
@@ -189,8 +196,8 @@ OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list,
// lldb_private::Process subclass, no memory threads will be in this list.
auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure threads_list stays alive
- PythonList threads_list(m_interpreter->OSPlugin_ThreadsInfo(m_python_object_sp));
-
+ StructuredData::ArraySP threads_list = m_interpreter->OSPlugin_ThreadsInfo(m_python_object_sp);
+
const uint32_t num_cores = core_thread_list.GetSize(false);
// Make a map so we can keep track of which cores were used from the
@@ -202,22 +209,19 @@ OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list,
if (log)
{
StreamString strm;
- threads_list.Dump(strm);
+ threads_list->Dump(strm);
log->Printf("threads_list = %s", strm.GetString().c_str());
}
- uint32_t i;
- const uint32_t num_threads = threads_list.GetSize();
- if (num_threads > 0)
+
+ const uint32_t num_threads = threads_list->GetSize();
+ for (uint32_t i = 0; i < num_threads; ++i)
{
- for (i=0; i<num_threads; ++i)
+ StructuredData::ObjectSP thread_dict_obj = threads_list->GetItemAtIndex(i);
+ if (auto thread_dict = thread_dict_obj->GetAsDictionary())
{
- PythonDictionary thread_dict(threads_list.GetItemAtIndex(i));
- if (thread_dict)
- {
- ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_dict, core_thread_list, old_thread_list, core_used_map, NULL));
- if (thread_sp)
- new_thread_list.AddThread(thread_sp);
- }
+ ThreadSP thread_sp(CreateThreadFromThreadInfo(*thread_dict, core_thread_list, old_thread_list, core_used_map, NULL));
+ if (thread_sp)
+ new_thread_list.AddThread(thread_sp);
}
}
}
@@ -239,79 +243,63 @@ OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list,
}
ThreadSP
-OperatingSystemPython::CreateThreadFromThreadInfo (PythonDictionary &thread_dict,
- ThreadList &core_thread_list,
- ThreadList &old_thread_list,
- std::vector<bool> &core_used_map,
- bool *did_create_ptr)
+OperatingSystemPython::CreateThreadFromThreadInfo(StructuredData::Dictionary &thread_dict, ThreadList &core_thread_list,
+ ThreadList &old_thread_list, std::vector<bool> &core_used_map, bool *did_create_ptr)
{
ThreadSP thread_sp;
- if (thread_dict)
+ tid_t tid = LLDB_INVALID_THREAD_ID;
+ if (!thread_dict.GetValueForKeyAsInteger("tid", tid))
+ return ThreadSP();
+
+ uint32_t core_number;
+ addr_t reg_data_addr;
+ std::string name;
+ std::string queue;
+
+ thread_dict.GetValueForKeyAsInteger("core", core_number, UINT32_MAX);
+ thread_dict.GetValueForKeyAsInteger("register_data_addr", reg_data_addr, LLDB_INVALID_ADDRESS);
+ thread_dict.GetValueForKeyAsString("name", name);
+ thread_dict.GetValueForKeyAsString("queue", queue);
+
+ // See if a thread already exists for "tid"
+ thread_sp = old_thread_list.FindThreadByID(tid, false);
+ if (thread_sp)
{
- PythonString tid_pystr("tid");
- const tid_t tid = thread_dict.GetItemForKeyAsInteger (tid_pystr, LLDB_INVALID_THREAD_ID);
- if (tid != LLDB_INVALID_THREAD_ID)
+ // A thread already does exist for "tid", make sure it was an operating system
+ // plug-in generated thread.
+ if (!IsOperatingSystemPluginThread(thread_sp))
{
- PythonString core_pystr("core");
- PythonString name_pystr("name");
- PythonString queue_pystr("queue");
- //PythonString state_pystr("state");
- //PythonString stop_reason_pystr("stop_reason");
- PythonString reg_data_addr_pystr ("register_data_addr");
-
- const uint32_t core_number = thread_dict.GetItemForKeyAsInteger (core_pystr, UINT32_MAX);
- const addr_t reg_data_addr = thread_dict.GetItemForKeyAsInteger (reg_data_addr_pystr, LLDB_INVALID_ADDRESS);
- const char *name = thread_dict.GetItemForKeyAsString (name_pystr);
- const char *queue = thread_dict.GetItemForKeyAsString (queue_pystr);
- //const char *state = thread_dict.GetItemForKeyAsString (state_pystr);
- //const char *stop_reason = thread_dict.GetItemForKeyAsString (stop_reason_pystr);
-
- // See if a thread already exists for "tid"
- thread_sp = old_thread_list.FindThreadByID (tid, false);
- if (thread_sp)
- {
- // A thread already does exist for "tid", make sure it was an operating system
- // plug-in generated thread.
- if (!IsOperatingSystemPluginThread(thread_sp))
- {
- // We have thread ID overlap between the protocol threads and the
- // operating system threads, clear the thread so we create an
- // operating system thread for this.
- thread_sp.reset();
- }
- }
-
- if (!thread_sp)
+ // We have thread ID overlap between the protocol threads and the
+ // operating system threads, clear the thread so we create an
+ // operating system thread for this.
+ thread_sp.reset();
+ }
+ }
+
+ if (!thread_sp)
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+ thread_sp.reset(new ThreadMemory(*m_process, tid, name.c_str(), queue.c_str(), reg_data_addr));
+ }
+
+ if (core_number < core_thread_list.GetSize(false))
+ {
+ ThreadSP core_thread_sp(core_thread_list.GetThreadAtIndex(core_number, false));
+ if (core_thread_sp)
+ {
+ // Keep track of which cores were set as the backing thread for memory threads...
+ if (core_number < core_used_map.size())
+ core_used_map[core_number] = true;
+
+ ThreadSP backing_core_thread_sp(core_thread_sp->GetBackingThread());
+ if (backing_core_thread_sp)
{
- if (did_create_ptr)
- *did_create_ptr = true;
- thread_sp.reset (new ThreadMemory (*m_process,
- tid,
- name,
- queue,
- reg_data_addr));
-
+ thread_sp->SetBackingThread(backing_core_thread_sp);
}
-
- if (core_number < core_thread_list.GetSize(false))
+ else
{
- ThreadSP core_thread_sp (core_thread_list.GetThreadAtIndex(core_number, false));
- if (core_thread_sp)
- {
- // Keep track of which cores were set as the backing thread for memory threads...
- if (core_number < core_used_map.size())
- core_used_map[core_number] = true;
-
- ThreadSP backing_core_thread_sp (core_thread_sp->GetBackingThread());
- if (backing_core_thread_sp)
- {
- thread_sp->SetBackingThread(backing_core_thread_sp);
- }
- else
- {
- thread_sp->SetBackingThread(core_thread_sp);
- }
- }
+ thread_sp->SetBackingThread(core_thread_sp);
}
}
}
@@ -364,11 +352,11 @@ OperatingSystemPython::CreateRegisterContextForThread (Thread *thread, addr_t re
thread->GetID(),
thread->GetProtocolID());
- PythonString reg_context_data(m_interpreter->OSPlugin_RegisterContextData (m_python_object_sp, thread->GetID()));
+ StructuredData::StringSP reg_context_data = m_interpreter->OSPlugin_RegisterContextData(m_python_object_sp, thread->GetID());
if (reg_context_data)
{
- DataBufferSP data_sp (new DataBufferHeap (reg_context_data.GetString(),
- reg_context_data.GetSize()));
+ std::string value = reg_context_data->GetValue();
+ DataBufferSP data_sp(new DataBufferHeap(value.c_str(), value.length()));
if (data_sp->GetByteSize())
{
RegisterContextMemory *reg_ctx_memory = new RegisterContextMemory (*thread, 0, *GetDynamicRegisterInfo (), LLDB_INVALID_ADDRESS);
@@ -417,14 +405,14 @@ OperatingSystemPython::CreateThread (lldb::tid_t tid, addr_t context)
Mutex::Locker api_locker (target.GetAPIMutex());
auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure thread_info_dict stays alive
- PythonDictionary thread_info_dict (m_interpreter->OSPlugin_CreateThread(m_python_object_sp, tid, context));
+ StructuredData::DictionarySP thread_info_dict = m_interpreter->OSPlugin_CreateThread(m_python_object_sp, tid, context);
std::vector<bool> core_used_map;
if (thread_info_dict)
{
ThreadList core_threads(m_process);
ThreadList &thread_list = m_process->GetThreadList();
bool did_create = false;
- ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_info_dict, core_threads, thread_list, core_used_map, &did_create));
+ ThreadSP thread_sp(CreateThreadFromThreadInfo(*thread_info_dict, core_threads, thread_list, core_used_map, &did_create));
if (did_create)
thread_list.AddThread(thread_sp);
return thread_sp;
diff --git a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
index 3b7dd264dc62..e29bf8054f6c 100644
--- a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
+++ b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
@@ -14,11 +14,16 @@
// C Includes
// C++ Includes
// Other libraries and framework includes
-#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Target/OperatingSystem.h"
class DynamicRegisterInfo;
+namespace lldb_private
+{
+class ScriptInterpreter;
+}
+
class OperatingSystemPython : public lldb_private::OperatingSystem
{
public:
@@ -86,15 +91,12 @@ protected:
bool IsValid() const
{
- return m_python_object_sp && m_python_object_sp->GetObject() != NULL;
+ return m_python_object_sp && m_python_object_sp->IsValid();
}
-
- lldb::ThreadSP
- CreateThreadFromThreadInfo (lldb_private::PythonDictionary &thread_dict,
- lldb_private::ThreadList &core_thread_list,
- lldb_private::ThreadList &old_thread_list,
- std::vector<bool> &core_used_map,
- bool *did_create_ptr);
+
+ lldb::ThreadSP CreateThreadFromThreadInfo(lldb_private::StructuredData::Dictionary &thread_dict,
+ lldb_private::ThreadList &core_thread_list, lldb_private::ThreadList &old_thread_list,
+ std::vector<bool> &core_used_map, bool *did_create_ptr);
DynamicRegisterInfo *
GetDynamicRegisterInfo ();
@@ -102,8 +104,7 @@ protected:
lldb::ValueObjectSP m_thread_list_valobj_sp;
std::unique_ptr<DynamicRegisterInfo> m_register_info_ap;
lldb_private::ScriptInterpreter *m_interpreter;
- lldb::ScriptInterpreterObjectSP m_python_object_sp;
-
+ lldb_private::StructuredData::ObjectSP m_python_object_sp;
};
#endif // #ifndef liblldb_OperatingSystemPython_h_
diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
index 3b38a5819934..9b3c57501117 100644
--- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
+++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "PlatformFreeBSD.h"
#include "lldb/Host/Config.h"
@@ -21,6 +19,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
@@ -28,12 +28,14 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Process.h"
using namespace lldb;
using namespace lldb_private;
+using namespace lldb_private::platform_freebsd;
PlatformSP
-PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
+PlatformFreeBSD::CreateInstance(bool force, const ArchSpec *arch)
{
// The only time we create an instance is when we are creating a remote
// freebsd platform
@@ -43,45 +45,23 @@ PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
if (create == false && arch && arch->IsValid())
{
const llvm::Triple &triple = arch->GetTriple();
- switch (triple.getVendor())
+ switch (triple.getOS())
{
- case llvm::Triple::PC:
+ case llvm::Triple::FreeBSD:
create = true;
break;
#if defined(__FreeBSD__) || defined(__OpenBSD__)
- // Only accept "unknown" for the vendor if the host is BSD and
+ // Only accept "unknown" for the OS if the host is BSD and
// it "unknown" wasn't specified (it was just returned because it
// was NOT specified)
- case llvm::Triple::UnknownArch:
- create = !arch->TripleVendorWasSpecified();
+ case llvm::Triple::OSType::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
break;
#endif
default:
break;
}
-
- if (create)
- {
- switch (triple.getOS())
- {
- 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 because it
- // was NOT specified)
- case llvm::Triple::UnknownOS:
- create = arch->TripleOSWasSpecified();
- break;
-#endif
- default:
- create = false;
- break;
- }
- }
}
if (create)
return PlatformSP(new PlatformFreeBSD (is_host));
@@ -89,8 +69,8 @@ PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
}
-lldb_private::ConstString
-PlatformFreeBSD::GetPluginNameStatic (bool is_host)
+ConstString
+PlatformFreeBSD::GetPluginNameStatic(bool is_host)
{
if (is_host)
{
@@ -118,6 +98,8 @@ static uint32_t g_initialize_count = 0;
void
PlatformFreeBSD::Initialize ()
{
+ Platform::Initialize ();
+
if (g_initialize_count++ == 0)
{
#if defined (__FreeBSD__)
@@ -137,35 +119,28 @@ PlatformFreeBSD::Terminate ()
{
if (g_initialize_count > 0 && --g_initialize_count == 0)
PluginManager::UnregisterPlugin (PlatformFreeBSD::CreateInstance);
-}
-//------------------------------------------------------------------
-/// Default Constructor
-//------------------------------------------------------------------
-PlatformFreeBSD::PlatformFreeBSD (bool is_host) :
-Platform(is_host),
-m_remote_platform_sp()
-{
+ Platform::Terminate ();
}
-//------------------------------------------------------------------
-/// Destructor.
-///
-/// The destructor is virtual since this class is designed to be
-/// inherited from by the plug-in instance.
-//------------------------------------------------------------------
-PlatformFreeBSD::~PlatformFreeBSD()
+bool
+PlatformFreeBSD::GetModuleSpec (const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec)
{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetModuleSpec (module_file_spec, arch, module_spec);
+
+ return Platform::GetModuleSpec (module_file_spec, arch, module_spec);
}
-//TODO:VK: inherit PlatformPOSIX
-lldb_private::Error
-PlatformFreeBSD::RunShellCommand (const char *command,
- const char *working_dir,
- int *status_ptr,
- int *signo_ptr,
- std::string *command_output,
- uint32_t timeout_sec)
+Error
+PlatformFreeBSD::RunShellCommand(const char *command,
+ const FileSpec &working_dir,
+ int *status_ptr,
+ int *signo_ptr,
+ std::string *command_output,
+ uint32_t timeout_sec)
{
if (IsHost())
return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
@@ -178,7 +153,6 @@ PlatformFreeBSD::RunShellCommand (const char *command,
}
}
-
Error
PlatformFreeBSD::ResolveExecutable (const ModuleSpec &module_spec,
lldb::ModuleSP &exe_module_sp,
@@ -214,9 +188,7 @@ PlatformFreeBSD::ResolveExecutable (const ModuleSpec &module_spec,
{
if (m_remote_platform_sp)
{
- error = m_remote_platform_sp->ResolveExecutable (module_spec,
- exe_module_sp,
- module_search_paths_ptr);
+ error = GetCachedExecutable (resolved_module_spec, exe_module_sp, module_search_paths_ptr, *m_remote_platform_sp);
}
else
{
@@ -301,41 +273,46 @@ PlatformFreeBSD::ResolveExecutable (const ModuleSpec &module_spec,
return error;
}
-size_t
-PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
+// From PlatformMacOSX only
+Error
+PlatformFreeBSD::GetFileWithUUID (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
{
- ArchSpec arch = target.GetArchitecture();
- const uint8_t *trap_opcode = NULL;
- size_t trap_opcode_size = 0;
-
- switch (arch.GetMachine())
+ if (IsRemote())
{
- default:
- assert(false && "Unhandled architecture in PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode()");
- break;
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- {
- static const uint8_t g_i386_opcode[] = { 0xCC };
- trap_opcode = g_i386_opcode;
- trap_opcode_size = sizeof(g_i386_opcode);
- }
- break;
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- {
- static const uint8_t g_ppc_opcode[] = { 0x7f, 0xe0, 0x00, 0x08 };
- trap_opcode = g_ppc_opcode;
- trap_opcode_size = sizeof(g_ppc_opcode);
- }
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file);
}
- if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
- return trap_opcode_size;
+ // Default to the local case
+ local_file = platform_file;
+ return Error();
+}
- return 0;
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformFreeBSD::PlatformFreeBSD (bool is_host) :
+ Platform(is_host),
+ m_remote_platform_sp()
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformFreeBSD::~PlatformFreeBSD()
+{
}
+//TODO:VK: inherit PlatformPOSIX
+
+
bool
PlatformFreeBSD::GetRemoteOSVersion ()
{
@@ -466,8 +443,6 @@ PlatformFreeBSD::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_i
return success;
}
-
-
uint32_t
PlatformFreeBSD::FindProcesses (const ProcessInstanceInfoMatch &match_info,
ProcessInstanceInfoList &process_infos)
@@ -487,71 +462,6 @@ PlatformFreeBSD::FindProcesses (const ProcessInstanceInfoMatch &match_info,
return match_count;
}
-Error
-PlatformFreeBSD::LaunchProcess (ProcessLaunchInfo &launch_info)
-{
- Error error;
- if (IsHost())
- {
- error = Platform::LaunchProcess (launch_info);
- }
- else
- {
- if (m_remote_platform_sp)
- error = m_remote_platform_sp->LaunchProcess (launch_info);
- else
- error.SetErrorString ("the platform is not currently connected");
- }
- return error;
-}
-
-lldb::ProcessSP
-PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
- Debugger &debugger,
- Target *target,
- Error &error)
-{
- lldb::ProcessSP process_sp;
- if (IsHost())
- {
- if (target == NULL)
- {
- TargetSP new_target_sp;
- ArchSpec emptyArchSpec;
-
- error = debugger.GetTargetList().CreateTarget (debugger,
- NULL,
- emptyArchSpec,
- false,
- m_remote_platform_sp,
- new_target_sp);
- target = new_target_sp.get();
- }
- else
- error.Clear();
-
- if (target && error.Success())
- {
- debugger.GetTargetList().SetSelectedTarget(target);
- // The freebsd always currently uses the GDB remote debugger plug-in
- // so even when debugging locally we are debugging remotely!
- // Just like the darwin plugin.
- process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
-
- if (process_sp)
- error = process_sp->Attach (attach_info);
- }
- }
- else
- {
- if (m_remote_platform_sp)
- process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error);
- else
- error.SetErrorString ("the platform is not currently connected");
- }
- return process_sp;
-}
-
const char *
PlatformFreeBSD::GetUserName (uint32_t uid)
{
@@ -578,25 +488,9 @@ PlatformFreeBSD::GetGroupName (uint32_t gid)
}
-// From PlatformMacOSX only
-Error
-PlatformFreeBSD::GetFileWithUUID (const FileSpec &platform_file,
- const UUID *uuid_ptr,
- FileSpec &local_file)
-{
- if (IsRemote())
- {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file);
- }
-
- // Default to the local case
- local_file = platform_file;
- return Error();
-}
-
Error
PlatformFreeBSD::GetSharedModule (const ModuleSpec &module_spec,
+ Process* process,
ModuleSP &module_sp,
const FileSpecList *module_search_paths_ptr,
ModuleSP *old_module_sp_ptr,
@@ -612,6 +506,7 @@ PlatformFreeBSD::GetSharedModule (const ModuleSpec &module_spec,
if (m_remote_platform_sp)
{
error = m_remote_platform_sp->GetSharedModule (module_spec,
+ process,
module_sp,
module_search_paths_ptr,
old_module_sp_ptr,
@@ -623,6 +518,7 @@ PlatformFreeBSD::GetSharedModule (const ModuleSpec &module_spec,
{
// Fall back to the local platform and find the file locally
error = Platform::GetSharedModule (module_spec,
+ process,
module_sp,
module_search_paths_ptr,
old_module_sp_ptr,
@@ -637,24 +533,56 @@ PlatformFreeBSD::GetSharedModule (const ModuleSpec &module_spec,
bool
PlatformFreeBSD::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
{
- // From macosx;s plugin code. For FreeBSD we may want to support more archs.
- if (idx == 0)
+ if (IsHost())
{
- arch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
- return arch.IsValid();
+ ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
+ if (hostArch.GetTriple().isOSFreeBSD())
+ {
+ if (idx == 0)
+ {
+ arch = hostArch;
+ return arch.IsValid();
+ }
+ else if (idx == 1)
+ {
+ // If the default host architecture is 64-bit, look for a 32-bit variant
+ if (hostArch.IsValid() && hostArch.GetTriple().isArch64Bit())
+ {
+ arch = HostInfo::GetArchitecture(HostInfo::eArchKind32);
+ return arch.IsValid();
+ }
+ }
+ }
}
- else if (idx == 1)
+ else
{
- ArchSpec platform_arch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
- ArchSpec platform_arch64(HostInfo::GetArchitecture(HostInfo::eArchKind64));
- if (platform_arch.IsExactMatch(platform_arch64))
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetSupportedArchitectureAtIndex(idx, arch);
+
+ llvm::Triple triple;
+ // Set the OS to FreeBSD
+ triple.setOS(llvm::Triple::FreeBSD);
+ // Set the architecture
+ switch (idx)
{
- // 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 = HostInfo::GetArchitecture(HostInfo::eArchKind32);
- return arch.IsValid();
+ case 0: triple.setArchName("x86_64"); break;
+ case 1: triple.setArchName("i386"); break;
+ case 2: triple.setArchName("aarch64"); break;
+ case 3: triple.setArchName("arm"); break;
+ case 4: triple.setArchName("mips64"); break;
+ case 5: triple.setArchName("mips"); break;
+ case 6: triple.setArchName("ppc64"); break;
+ case 7: triple.setArchName("ppc"); break;
+ default: return false;
}
+ // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the vendor by
+ // calling triple.SetVendorName("unknown") so that it is a "unspecified unknown".
+ // This means when someone calls triple.GetVendorName() it will return an empty string
+ // which indicates that the vendor can be set when two architectures are merged
+
+ // Now set the triple into "arch" and return true
+ arch.SetTriple(triple);
+ return true;
}
return false;
}
@@ -683,8 +611,157 @@ PlatformFreeBSD::GetStatus (Stream &strm)
Platform::GetStatus(strm);
}
+size_t
+PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
+{
+ ArchSpec arch = target.GetArchitecture();
+ const uint8_t *trap_opcode = NULL;
+ size_t trap_opcode_size = 0;
+
+ switch (arch.GetMachine())
+ {
+ default:
+ assert(false && "Unhandled architecture in PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode()");
+ break;
+ case llvm::Triple::aarch64:
+ {
+ static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xd4 };
+ trap_opcode = g_aarch64_opcode;
+ trap_opcode_size = sizeof(g_aarch64_opcode);
+ }
+ break;
+ // TODO: support big-endian arm and thumb trap codes.
+ case llvm::Triple::arm:
+ {
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xfe, 0xde, 0xff, 0xe7 };
+ static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde };
+
+ lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0));
+ AddressClass addr_class = eAddressClassUnknown;
+
+ if (bp_loc_sp)
+ addr_class = bp_loc_sp->GetAddress ().GetAddressClass ();
+
+ if (addr_class == eAddressClassCodeAlternateISA
+ || (addr_class == eAddressClassUnknown && (bp_site->GetLoadAddress() & 1)))
+ {
+ // TODO: Enable when FreeBSD supports thumb breakpoints.
+ // FreeBSD kernel as of 10.x, does not support thumb breakpoints
+ trap_opcode = g_thumb_breakpoint_opcode;
+ trap_opcode_size = 0;
+ }
+ else
+ {
+ trap_opcode = g_arm_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ }
+ }
+ break;
+ case llvm::Triple::mips64:
+ {
+ static const uint8_t g_hex_opcode[] = { 0x00, 0x00, 0x00, 0x0d };
+ trap_opcode = g_hex_opcode;
+ trap_opcode_size = sizeof(g_hex_opcode);
+ }
+ break;
+ case llvm::Triple::mips64el:
+ {
+ static const uint8_t g_hex_opcode[] = { 0x0d, 0x00, 0x00, 0x00 };
+ trap_opcode = g_hex_opcode;
+ trap_opcode_size = sizeof(g_hex_opcode);
+ }
+ break;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ {
+ static const uint8_t g_ppc_opcode[] = { 0x7f, 0xe0, 0x00, 0x08 };
+ trap_opcode = g_ppc_opcode;
+ trap_opcode_size = sizeof(g_ppc_opcode);
+ }
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ {
+ static const uint8_t g_i386_opcode[] = { 0xCC };
+ trap_opcode = g_i386_opcode;
+ trap_opcode_size = sizeof(g_i386_opcode);
+ }
+ break;
+ }
+
+ if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+ return 0;
+}
+
+
void
PlatformFreeBSD::CalculateTrapHandlerSymbolNames ()
{
m_trap_handlers.push_back (ConstString ("_sigtramp"));
}
+
+Error
+PlatformFreeBSD::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ if (IsHost())
+ {
+ error = Platform::LaunchProcess (launch_info);
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ error = m_remote_platform_sp->LaunchProcess (launch_info);
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return error;
+}
+
+lldb::ProcessSP
+PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
+ Debugger &debugger,
+ Target *target,
+ Error &error)
+{
+ lldb::ProcessSP process_sp;
+ if (IsHost())
+ {
+ if (target == NULL)
+ {
+ TargetSP new_target_sp;
+ ArchSpec emptyArchSpec;
+
+ error = debugger.GetTargetList().CreateTarget (debugger,
+ NULL,
+ emptyArchSpec,
+ false,
+ m_remote_platform_sp,
+ new_target_sp);
+ target = new_target_sp.get();
+ }
+ else
+ error.Clear();
+
+ if (target && error.Success())
+ {
+ debugger.GetTargetList().SetSelectedTarget(target);
+ // The freebsd always currently uses the GDB remote debugger plug-in
+ // so even when debugging locally we are debugging remotely!
+ // Just like the darwin plugin.
+ process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
+
+ if (process_sp)
+ error = process_sp->Attach (attach_info);
+ }
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error);
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return process_sp;
+}
diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
index ce3f8cfad976..67156e6ae37b 100644
--- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
+++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
@@ -16,156 +16,167 @@
// Project includes
#include "lldb/Target/Platform.h"
-class PlatformFreeBSD : public lldb_private::Platform
-{
-public:
- // Mostly taken from PlatformDarwin and PlatformMacOSX
-
- //------------------------------------------------------------
- // Class functions
- //------------------------------------------------------------
- static lldb::PlatformSP
- CreateInstance (bool force, const lldb_private::ArchSpec *arch);
-
- static void
- Initialize ();
-
- static void
- Terminate ();
-
- static lldb_private::ConstString
- GetPluginNameStatic (bool is_host);
-
- static const char *
- GetDescriptionStatic (bool is_host);
-
- //------------------------------------------------------------
- // Class Methods
- //------------------------------------------------------------
- PlatformFreeBSD (bool is_host);
-
- virtual
- ~PlatformFreeBSD();
-
- //------------------------------------------------------------
- // lldb_private::PluginInterface functions
- //------------------------------------------------------------
- virtual lldb_private::ConstString
- GetPluginName()
- {
- return GetPluginNameStatic (IsHost());
- }
-
- virtual uint32_t
- GetPluginVersion()
- {
- return 1;
- }
+namespace lldb_private {
+namespace platform_freebsd {
- virtual const char *
- GetDescription ()
+ class PlatformFreeBSD : public Platform
{
- return GetDescriptionStatic(IsHost());
- }
-
- //------------------------------------------------------------
- // lldb_private::Platform functions
- //------------------------------------------------------------
- virtual lldb_private::Error
- RunShellCommand (const char *command,
- const char *working_dir,
- int *status_ptr,
- int *signo_ptr,
- std::string *command_output,
- uint32_t timeout_sec);
-
- virtual lldb_private::Error
- ResolveExecutable (const lldb_private::ModuleSpec &module_spec,
- lldb::ModuleSP &module_sp,
- const lldb_private::FileSpecList *module_search_paths_ptr);
-
- virtual size_t
- GetSoftwareBreakpointTrapOpcode (lldb_private::Target &target,
- lldb_private::BreakpointSite *bp_site);
-
- virtual bool
- GetRemoteOSVersion ();
-
- virtual bool
- GetRemoteOSBuildString (std::string &s);
-
- virtual bool
- GetRemoteOSKernelDescription (std::string &s);
-
- // Remote Platform subclasses need to override this function
- virtual lldb_private::ArchSpec
- GetRemoteSystemArchitecture ();
-
- virtual bool
- IsConnected () const;
-
- virtual lldb_private::Error
- ConnectRemote (lldb_private::Args& args);
-
- virtual lldb_private::Error
- DisconnectRemote ();
-
- virtual const char *
- GetHostname ();
-
- virtual const char *
- GetUserName (uint32_t uid);
-
- virtual const char *
- GetGroupName (uint32_t gid);
-
- virtual bool
- GetProcessInfo (lldb::pid_t pid,
- lldb_private::ProcessInstanceInfo &proc_info);
-
- virtual uint32_t
- FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
- lldb_private::ProcessInstanceInfoList &process_infos);
-
- virtual lldb_private::Error
- LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info);
-
- virtual lldb::ProcessSP
- Attach(lldb_private::ProcessAttachInfo &attach_info,
- lldb_private::Debugger &debugger,
- lldb_private::Target *target,
- lldb_private::Error &error);
-
- // FreeBSD processes can not be launched by spawning and attaching.
- virtual bool
- CanDebugProcess () { return false; }
-
- // Only on PlatformMacOSX:
- virtual lldb_private::Error
- GetFileWithUUID (const lldb_private::FileSpec &platform_file,
- const lldb_private::UUID* uuid, lldb_private::FileSpec &local_file);
-
- lldb_private::Error
- GetSharedModule (const lldb_private::ModuleSpec &module_spec,
- lldb::ModuleSP &module_sp,
- const lldb_private::FileSpecList *module_search_paths_ptr,
- lldb::ModuleSP *old_module_sp_ptr,
- bool *did_create_ptr);
-
- virtual bool
- GetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch);
-
- virtual void
- GetStatus (lldb_private::Stream &strm);
+ public:
+
+ //------------------------------------------------------------
+ // Class functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance(bool force, const ArchSpec *arch);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static ConstString
+ GetPluginNameStatic (bool is_host);
+
+ static const char *
+ GetDescriptionStatic (bool is_host);
+
+ //------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------
+ PlatformFreeBSD (bool is_host);
+
+ virtual
+ ~PlatformFreeBSD();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ ConstString
+ GetPluginName() override
+ {
+ return GetPluginNameStatic (IsHost());
+ }
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ const char *
+ GetDescription () override
+ {
+ return GetDescriptionStatic(IsHost());
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ bool
+ GetModuleSpec(const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec) override;
+
+ Error
+ RunShellCommand(const char *command,
+ const FileSpec &working_dir,
+ int *status_ptr,
+ int *signo_ptr,
+ std::string *command_output,
+ uint32_t timeout_sec) override;
+
+ Error
+ ResolveExecutable(const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr) override;
+
+ size_t
+ GetSoftwareBreakpointTrapOpcode(Target &target,
+ BreakpointSite *bp_site) override;
+
+ bool
+ GetRemoteOSVersion () override;
+
+ bool
+ GetRemoteOSBuildString (std::string &s) override;
+
+ bool
+ GetRemoteOSKernelDescription (std::string &s) override;
+
+ // Remote Platform subclasses need to override this function
+ ArchSpec
+ GetRemoteSystemArchitecture() override;
+
+ bool
+ IsConnected () const override;
+
+ Error
+ ConnectRemote(Args& args) override;
+
+ Error
+ DisconnectRemote() override;
+
+ const char *
+ GetHostname () override;
+
+ const char *
+ GetUserName (uint32_t uid) override;
+
+ const char *
+ GetGroupName (uint32_t gid) override;
+
+ bool
+ GetProcessInfo(lldb::pid_t pid,
+ ProcessInstanceInfo &proc_info) override;
+
+ uint32_t
+ FindProcesses(const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos) override;
+
+ Error
+ LaunchProcess(ProcessLaunchInfo &launch_info) override;
+
+ lldb::ProcessSP
+ Attach(ProcessAttachInfo &attach_info,
+ Debugger &debugger,
+ Target *target,
+ Error &error) override;
+
+ // FreeBSD processes can not be launched by spawning and attaching.
+ bool
+ CanDebugProcess () override { return false; }
+
+ // Only on PlatformMacOSX:
+ Error
+ GetFileWithUUID(const FileSpec &platform_file,
+ const UUID* uuid, FileSpec &local_file) override;
+
+ Error
+ GetSharedModule(const ModuleSpec &module_spec,
+ Process* process,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) override;
+
+ bool
+ GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override;
+
+ void
+ GetStatus(Stream &strm) override;
+
+ void
+ CalculateTrapHandlerSymbolNames () override;
- virtual void
- CalculateTrapHandlerSymbolNames ();
+ protected:
+ lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote freebsd OS
-protected:
- lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote freebsd OS
+ private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformFreeBSD);
+ };
-private:
- DISALLOW_COPY_AND_ASSIGN (PlatformFreeBSD);
-};
+} // namespace platform_freebsd
+} // namespace lldb_private
#endif // liblldb_PlatformFreeBSD_h_
diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
index 5b72728c2b48..fe425e02103b 100644
--- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
+++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
@@ -24,6 +24,7 @@
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/ProcessLaunchInfo.h"
using namespace lldb;
@@ -49,6 +50,17 @@ PlatformPOSIX::~PlatformPOSIX()
{
}
+bool
+PlatformPOSIX::GetModuleSpec (const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec)
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetModuleSpec (module_file_spec, arch, module_spec);
+
+ return Platform::GetModuleSpec (module_file_spec, arch, module_spec);
+}
+
lldb_private::OptionGroupOptions*
PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpreter)
{
@@ -73,12 +85,12 @@ PlatformPOSIX::IsConnected () const
}
lldb_private::Error
-PlatformPOSIX::RunShellCommand (const char *command, // Shouldn't be NULL
- const char *working_dir, // Pass NULL to use the current working directory
- int *status_ptr, // Pass NULL if you don't want the process exit status
- int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
- std::string *command_output, // Pass NULL if you don't want the command output
- uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
+PlatformPOSIX::RunShellCommand(const char *command, // Shouldn't be NULL
+ const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
{
if (IsHost())
return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
@@ -92,30 +104,30 @@ PlatformPOSIX::RunShellCommand (const char *command, // Shouldn't be N
}
Error
-PlatformPOSIX::MakeDirectory (const char *path, uint32_t file_permissions)
+PlatformPOSIX::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions)
{
if (m_remote_platform_sp)
- return m_remote_platform_sp->MakeDirectory(path, file_permissions);
+ return m_remote_platform_sp->MakeDirectory(file_spec, file_permissions);
else
- return Platform::MakeDirectory(path ,file_permissions);
+ return Platform::MakeDirectory(file_spec ,file_permissions);
}
Error
-PlatformPOSIX::GetFilePermissions (const char *path, uint32_t &file_permissions)
+PlatformPOSIX::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions)
{
if (m_remote_platform_sp)
- return m_remote_platform_sp->GetFilePermissions(path, file_permissions);
+ return m_remote_platform_sp->GetFilePermissions(file_spec, file_permissions);
else
- return Platform::GetFilePermissions(path ,file_permissions);
+ return Platform::GetFilePermissions(file_spec ,file_permissions);
}
Error
-PlatformPOSIX::SetFilePermissions (const char *path, uint32_t file_permissions)
+PlatformPOSIX::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions)
{
if (m_remote_platform_sp)
- return m_remote_platform_sp->SetFilePermissions(path, file_permissions);
+ return m_remote_platform_sp->SetFilePermissions(file_spec, file_permissions);
else
- return Platform::SetFilePermissions(path ,file_permissions);
+ return Platform::SetFilePermissions(file_spec, file_permissions);
}
lldb::user_id_t
@@ -304,7 +316,7 @@ PlatformPOSIX::GetFileSize (const FileSpec& file_spec)
}
Error
-PlatformPOSIX::CreateSymlink(const char *src, const char *dst)
+PlatformPOSIX::CreateSymlink(const FileSpec &src, const FileSpec &dst)
{
if (IsHost())
return FileSystem::Symlink(src, dst);
@@ -326,19 +338,19 @@ PlatformPOSIX::GetFileExists (const FileSpec& file_spec)
}
Error
-PlatformPOSIX::Unlink (const char *path)
+PlatformPOSIX::Unlink(const FileSpec &file_spec)
{
if (IsHost())
- return FileSystem::Unlink(path);
+ return FileSystem::Unlink(file_spec);
else if (m_remote_platform_sp)
- return m_remote_platform_sp->Unlink(path);
+ return m_remote_platform_sp->Unlink(file_spec);
else
- return Platform::Unlink(path);
+ return Platform::Unlink(file_spec);
}
lldb_private::Error
-PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path */,
- const lldb_private::FileSpec& destination /* local file path */)
+PlatformPOSIX::GetFile(const lldb_private::FileSpec &source, // remote file path
+ const lldb_private::FileSpec &destination) // local file path
{
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
@@ -421,8 +433,8 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path
return Error("unable to open source file");
uint32_t permissions = 0;
- error = GetFilePermissions(source.GetPath().c_str(), permissions);
-
+ error = GetFilePermissions(source, permissions);
+
if (permissions == 0)
permissions = lldb::eFilePermissionsFileDefault;
@@ -523,7 +535,7 @@ PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec,
return false;
}
-lldb_private::ConstString
+FileSpec
PlatformPOSIX::GetRemoteWorkingDirectory()
{
if (IsRemote() && m_remote_platform_sp)
@@ -533,12 +545,12 @@ PlatformPOSIX::GetRemoteWorkingDirectory()
}
bool
-PlatformPOSIX::SetRemoteWorkingDirectory(const lldb_private::ConstString &path)
+PlatformPOSIX::SetRemoteWorkingDirectory(const FileSpec &working_dir)
{
if (IsRemote() && m_remote_platform_sp)
- return m_remote_platform_sp->SetRemoteWorkingDirectory(path);
+ return m_remote_platform_sp->SetRemoteWorkingDirectory(working_dir);
else
- return Platform::SetRemoteWorkingDirectory(path);
+ return Platform::SetRemoteWorkingDirectory(working_dir);
}
bool
@@ -653,9 +665,9 @@ PlatformPOSIX::ConnectRemote (Args& args)
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');
+ const OptionGroupPlatformRSync* m_rsync_options = (OptionGroupPlatformRSync*)options->GetGroupWithOption('r');
+ const OptionGroupPlatformSSH* m_ssh_options = (OptionGroupPlatformSSH*)options->GetGroupWithOption('s');
+ const OptionGroupPlatformCaching* m_cache_options = (OptionGroupPlatformCaching*)options->GetGroupWithOption('c');
if (m_rsync_options->m_rsync)
{
@@ -714,6 +726,18 @@ PlatformPOSIX::LaunchProcess (ProcessLaunchInfo &launch_info)
return error;
}
+lldb_private::Error
+PlatformPOSIX::KillProcess (const lldb::pid_t pid)
+{
+ if (IsHost())
+ return Platform::KillProcess (pid);
+
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->KillProcess (pid);
+
+ return Error ("the platform is not currently connected");
+}
+
lldb::ProcessSP
PlatformPOSIX::Attach (ProcessAttachInfo &attach_info,
Debugger &debugger,
@@ -752,9 +776,8 @@ PlatformPOSIX::Attach (ProcessAttachInfo &attach_info,
if (log)
{
ModuleSP exe_module_sp = target->GetExecutableModule ();
- log->Printf ("PlatformPOSIX::%s set selected target to %p %s", __FUNCTION__,
- target,
- exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<null>" );
+ log->Printf("PlatformPOSIX::%s set selected target to %p %s", __FUNCTION__, (void *)target,
+ exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str() : "<null>");
}
diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h
index aae415e6eefa..19a3f0c4eef1 100644
--- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h
+++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h
@@ -31,7 +31,13 @@ public:
//------------------------------------------------------------
// lldb_private::Platform functions
//------------------------------------------------------------
- virtual lldb_private::OptionGroupOptions
+
+ bool
+ GetModuleSpec (const lldb_private::FileSpec& module_file_spec,
+ const lldb_private::ArchSpec& arch,
+ lldb_private::ModuleSpec &module_spec) override;
+
+ lldb_private::OptionGroupOptions
*GetConnectionOptions(
lldb_private::CommandInterpreter &interpreter) override;
@@ -44,51 +50,52 @@ public:
const char *
GetGroupName (uint32_t gid) override;
- virtual lldb_private::Error
+ lldb_private::Error
PutFile (const lldb_private::FileSpec& source,
const lldb_private::FileSpec& destination,
uint32_t uid = UINT32_MAX,
uint32_t gid = UINT32_MAX) override;
- virtual lldb::user_id_t
+ lldb::user_id_t
OpenFile (const lldb_private::FileSpec& file_spec,
uint32_t flags,
uint32_t mode,
lldb_private::Error &error) override;
- virtual bool
+ bool
CloseFile (lldb::user_id_t fd,
lldb_private::Error &error) override;
- virtual uint64_t
+ uint64_t
ReadFile (lldb::user_id_t fd,
uint64_t offset,
void *dst,
uint64_t dst_len,
lldb_private::Error &error) override;
- virtual uint64_t
+ uint64_t
WriteFile (lldb::user_id_t fd,
uint64_t offset,
const void* src,
uint64_t src_len,
lldb_private::Error &error) override;
- virtual lldb::user_id_t
+ lldb::user_id_t
GetFileSize (const lldb_private::FileSpec& file_spec) override;
- virtual lldb_private::Error
- CreateSymlink(const char *src, const char *dst) override;
+ lldb_private::Error
+ CreateSymlink(const lldb_private::FileSpec &src,
+ const lldb_private::FileSpec &dst) override;
+
+ lldb_private::Error
+ GetFile(const lldb_private::FileSpec &source,
+ const lldb_private::FileSpec &destination) override;
- virtual lldb_private::Error
- GetFile (const lldb_private::FileSpec& source,
- const lldb_private::FileSpec& destination) override;
-
- virtual lldb_private::ConstString
+ lldb_private::FileSpec
GetRemoteWorkingDirectory() override;
- virtual bool
- SetRemoteWorkingDirectory(const lldb_private::ConstString &path) override;
+ bool
+ SetRemoteWorkingDirectory(const lldb_private::FileSpec &working_dir) override;
bool
GetRemoteOSVersion () override;
@@ -108,32 +115,35 @@ public:
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
- int *status_ptr, // Pass NULL if you don't want the process exit status
- int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
- std::string *command_output, // Pass NULL if you don't want the command output
- uint32_t timeout_sec) override;// Timeout in seconds to wait for shell program to finish
-
- virtual lldb_private::Error
- MakeDirectory (const char *path, uint32_t mode) override;
-
- virtual lldb_private::Error
- GetFilePermissions (const char *path, uint32_t &file_permissions) override;
+ lldb_private::Error
+ RunShellCommand(const char *command, // Shouldn't be NULL
+ const lldb_private::FileSpec &working_dir, // Pass empty FileSpec to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec) override; // Timeout in seconds to wait for shell program to finish
+
+ lldb_private::Error
+ MakeDirectory(const lldb_private::FileSpec &file_spec, uint32_t mode) override;
- virtual lldb_private::Error
- SetFilePermissions (const char *path, uint32_t file_permissions) override;
+ lldb_private::Error
+ GetFilePermissions(const lldb_private::FileSpec &file_spec, uint32_t &file_permissions) override;
+
+ lldb_private::Error
+ SetFilePermissions(const lldb_private::FileSpec &file_spec, uint32_t file_permissions) override;
- virtual bool
+ bool
GetFileExists (const lldb_private::FileSpec& file_spec) override;
- virtual lldb_private::Error
- Unlink (const char *path) override;
+ lldb_private::Error
+ Unlink(const lldb_private::FileSpec &file_spec) override;
lldb_private::Error
LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info) override;
+ lldb_private::Error
+ KillProcess (const lldb::pid_t pid) override;
+
lldb::ProcessSP
Attach (lldb_private::ProcessAttachInfo &attach_info,
lldb_private::Debugger &debugger,
@@ -146,15 +156,15 @@ public:
lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one
lldb_private::Error &error) override;
- virtual std::string
+ std::string
GetPlatformSpecificConnectionInformation() override;
- virtual bool
+ bool
CalculateMD5 (const lldb_private::FileSpec& file_spec,
uint64_t &low,
uint64_t &high) override;
- virtual void
+ void
CalculateTrapHandlerSymbolNames () override;
lldb_private::Error
diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
index ec2084aaf98c..df0484c4e69b 100644
--- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
+++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "PlatformRemoteGDBServer.h"
#include "lldb/Host/Config.h"
@@ -27,6 +25,8 @@
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/StringConvert.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
@@ -34,12 +34,32 @@
using namespace lldb;
using namespace lldb_private;
+using namespace lldb_private::platform_gdb_server;
static bool g_initialized = false;
+static std::string MakeGdbServerUrl(
+ const std::string &platform_scheme,
+ const std::string &platform_hostname,
+ uint16_t port)
+{
+ const char *override_scheme = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME");
+ const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
+ const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
+ int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
+ StreamString result;
+ result.Printf("%s://%s:%u",
+ override_scheme ? override_scheme : platform_scheme.c_str(),
+ override_hostname ? override_hostname : platform_hostname.c_str(),
+ port + port_offset);
+ return result.GetString();
+}
+
void
PlatformRemoteGDBServer::Initialize ()
{
+ Platform::Initialize ();
+
if (g_initialized == false)
{
g_initialized = true;
@@ -57,10 +77,12 @@ PlatformRemoteGDBServer::Terminate ()
g_initialized = false;
PluginManager::UnregisterPlugin (PlatformRemoteGDBServer::CreateInstance);
}
+
+ Platform::Terminate ();
}
PlatformSP
-PlatformRemoteGDBServer::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
+PlatformRemoteGDBServer::CreateInstance (bool force, const ArchSpec *arch)
{
bool create = force;
if (!create)
@@ -73,7 +95,7 @@ PlatformRemoteGDBServer::CreateInstance (bool force, const lldb_private::ArchSpe
}
-lldb_private::ConstString
+ConstString
PlatformRemoteGDBServer::GetPluginNameStatic()
{
static ConstString g_name("remote-gdb-server");
@@ -180,6 +202,34 @@ PlatformRemoteGDBServer::ResolveExecutable (const ModuleSpec &module_spec,
return error;
}
+bool
+PlatformRemoteGDBServer::GetModuleSpec (const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec)
+{
+ Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM);
+
+ const auto module_path = module_file_spec.GetPath (false);
+
+ if (!m_gdb_client.GetModuleInfo (module_file_spec, arch, module_spec))
+ {
+ if (log)
+ log->Printf ("PlatformRemoteGDBServer::%s - failed to get module info for %s:%s",
+ __FUNCTION__, module_path.c_str (), arch.GetTriple ().getTriple ().c_str ());
+ return false;
+ }
+
+ if (log)
+ {
+ StreamString stream;
+ module_spec.Dump (stream);
+ log->Printf ("PlatformRemoteGDBServer::%s - got module info for (%s:%s) : %s",
+ __FUNCTION__, module_path.c_str (), arch.GetTriple ().getTriple ().c_str (), stream.GetString ().c_str ());
+ }
+
+ return true;
+}
+
Error
PlatformRemoteGDBServer::GetFileWithUUID (const FileSpec &platform_file,
const UUID *uuid_ptr,
@@ -194,8 +244,8 @@ PlatformRemoteGDBServer::GetFileWithUUID (const FileSpec &platform_file,
/// Default Constructor
//------------------------------------------------------------------
PlatformRemoteGDBServer::PlatformRemoteGDBServer () :
- Platform(false), // This is a remote platform
- m_gdb_client(true)
+ Platform (false), // This is a remote platform
+ m_gdb_client ()
{
}
@@ -214,12 +264,15 @@ PlatformRemoteGDBServer::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec
{
ArchSpec remote_arch = m_gdb_client.GetSystemArchitecture();
- // TODO: 64 bit systems should also advertize support for 32 bit arch
- // unknown CPU, we just support the one arch
if (idx == 0)
{
arch = remote_arch;
- return true;
+ return arch.IsValid();
+ }
+ else if (idx == 1 && remote_arch.IsValid() && remote_arch.GetTriple().isArch64Bit())
+ {
+ arch.SetTriple(remote_arch.GetTriple().get32BitArchVariant());
+ return arch.IsValid();
}
return false;
}
@@ -265,24 +318,17 @@ PlatformRemoteGDBServer::GetRemoteSystemArchitecture ()
return m_gdb_client.GetSystemArchitecture();
}
-lldb_private::ConstString
+FileSpec
PlatformRemoteGDBServer::GetRemoteWorkingDirectory()
{
if (IsConnected())
{
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
- std::string cwd;
- if (m_gdb_client.GetWorkingDir(cwd))
- {
- ConstString working_dir(cwd.c_str());
- if (log)
- log->Printf("PlatformRemoteGDBServer::GetRemoteWorkingDirectory() -> '%s'", working_dir.GetCString());
- return working_dir;
- }
- else
- {
- return ConstString();
- }
+ FileSpec working_dir;
+ if (m_gdb_client.GetWorkingDir(working_dir) && log)
+ log->Printf("PlatformRemoteGDBServer::GetRemoteWorkingDirectory() -> '%s'",
+ working_dir.GetCString());
+ return working_dir;
}
else
{
@@ -291,7 +337,7 @@ PlatformRemoteGDBServer::GetRemoteWorkingDirectory()
}
bool
-PlatformRemoteGDBServer::SetRemoteWorkingDirectory(const lldb_private::ConstString &path)
+PlatformRemoteGDBServer::SetRemoteWorkingDirectory(const FileSpec &working_dir)
{
if (IsConnected())
{
@@ -299,11 +345,12 @@ PlatformRemoteGDBServer::SetRemoteWorkingDirectory(const lldb_private::ConstStri
// for use to re-read it
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
- log->Printf("PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')", path.GetCString());
- return m_gdb_client.SetWorkingDir(path.GetCString()) == 0;
+ log->Printf("PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')",
+ working_dir.GetCString());
+ return m_gdb_client.SetWorkingDir(working_dir) == 0;
}
else
- return Platform::SetRemoteWorkingDirectory(path);
+ return Platform::SetRemoteWorkingDirectory(working_dir);
}
bool
@@ -325,18 +372,15 @@ PlatformRemoteGDBServer::ConnectRemote (Args& args)
{
if (args.GetArgumentCount() == 1)
{
- const char *url = args.GetArgumentAtIndex(0);
- m_gdb_client.SetConnection (new ConnectionFileDescriptor());
-
+ m_gdb_client.SetConnection(new ConnectionFileDescriptor());
// we're going to reuse the hostname when we connect to the debugserver
- std::string scheme;
int port;
std::string path;
- if ( !UriParser::Parse(url, scheme, m_platform_hostname, port, path) )
- {
- error.SetErrorString("invalid uri");
- return error;
- }
+ const char *url = args.GetArgumentAtIndex(0);
+ if (!url)
+ return Error("URL is null.");
+ if (!UriParser::Parse(url, m_platform_scheme, m_platform_hostname, port, path))
+ return Error("Invalid URL: %s", url);
const ConnectionStatus status = m_gdb_client.Connect(url, &error);
if (status == eConnectionStatusSuccess)
@@ -346,7 +390,7 @@ PlatformRemoteGDBServer::ConnectRemote (Args& args)
m_gdb_client.GetHostInfo();
// If a working directory was set prior to connecting, send it down now
if (m_working_dir)
- m_gdb_client.SetWorkingDir(m_working_dir.GetCString());
+ m_gdb_client.SetWorkingDir(m_working_dir);
}
else
{
@@ -361,7 +405,6 @@ PlatformRemoteGDBServer::ConnectRemote (Args& args)
error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
}
}
-
return error;
}
@@ -428,7 +471,7 @@ PlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &p
Error
PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
Error error;
if (log)
@@ -443,13 +486,13 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
switch(file_action->GetFD())
{
case STDIN_FILENO:
- m_gdb_client.SetSTDIN (file_action->GetPath());
+ m_gdb_client.SetSTDIN(file_action->GetFileSpec());
break;
case STDOUT_FILENO:
- m_gdb_client.SetSTDOUT (file_action->GetPath());
+ m_gdb_client.SetSTDOUT(file_action->GetFileSpec());
break;
case STDERR_FILENO:
- m_gdb_client.SetSTDERR (file_action->GetPath());
+ m_gdb_client.SetSTDERR(file_action->GetFileSpec());
break;
}
}
@@ -457,10 +500,10 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
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])
+ FileSpec working_dir = launch_info.GetWorkingDirectory();
+ if (working_dir)
{
- m_gdb_client.SetWorkingDir (working_dir);
+ m_gdb_client.SetWorkingDir(working_dir);
}
// Send the environment and the program + arguments after we connect
@@ -483,9 +526,13 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
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);
+ int arg_packet_err;
+ {
+ // Scope for the scoped timeout object
+ process_gdb_remote::GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_client, 5);
+ arg_packet_err = m_gdb_client.SendArgumentsPacket (launch_info);
+ }
+
if (arg_packet_err == 0)
{
std::string error_str;
@@ -522,16 +569,16 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
Error
PlatformRemoteGDBServer::KillProcess (const lldb::pid_t pid)
{
- if (!m_gdb_client.KillSpawnedProcess(pid))
+ if (!KillSpawnedProcess(pid))
return Error("failed to kill remote spawned process");
return Error();
}
lldb::ProcessSP
-PlatformRemoteGDBServer::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::Error &error)
+PlatformRemoteGDBServer::DebugProcess (ProcessLaunchInfo &launch_info,
+ Debugger &debugger,
+ Target *target, // Can be NULL, if NULL create a new target, else use existing one
+ Error &error)
{
lldb::ProcessSP process_sp;
if (IsRemote())
@@ -539,22 +586,8 @@ PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_i
if (IsConnected())
{
lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
- ArchSpec remote_arch = GetRemoteSystemArchitecture();
- llvm::Triple &remote_triple = remote_arch.GetTriple();
- uint16_t port = 0;
- if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS)
- {
- // 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, "127.0.0.1");
- }
- else
- {
- // All other hosts should use their actual hostname
- port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL);
- }
-
+ uint16_t port = LaunchGDBserverAndGetPort(debugserver_pid);
+
if (port == 0)
{
error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
@@ -586,26 +619,18 @@ PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_i
if (process_sp)
{
- char connect_url[256];
- const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
- const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
- int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
- const int connect_url_len = ::snprintf (connect_url,
- sizeof(connect_url),
- "connect://%s:%u",
- override_hostname ? override_hostname : m_platform_hostname.c_str(),
- port + port_offset);
- assert (connect_url_len < (int)sizeof(connect_url));
- error = process_sp->ConnectRemote (NULL, connect_url);
+ std::string connect_url =
+ MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port);
+ error = process_sp->ConnectRemote (nullptr, connect_url.c_str());
// Retry the connect remote one time...
if (error.Fail())
- error = process_sp->ConnectRemote (NULL, connect_url);
+ error = process_sp->ConnectRemote (nullptr, connect_url.c_str());
if (error.Success())
error = process_sp->Launch(launch_info);
else if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
{
printf ("error: connect remote failed (%s)\n", error.AsCString());
- m_gdb_client.KillSpawnedProcess(debugserver_pid);
+ KillSpawnedProcess(debugserver_pid);
}
}
}
@@ -617,11 +642,36 @@ PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_i
}
}
return process_sp;
-
+
+}
+
+uint16_t
+PlatformRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
+{
+ ArchSpec remote_arch = GetRemoteSystemArchitecture ();
+ llvm::Triple &remote_triple = remote_arch.GetTriple ();
+ if (remote_triple.getVendor () == llvm::Triple::Apple && remote_triple.getOS () == llvm::Triple::IOS)
+ {
+ // 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
+ return m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1");
+ }
+ else
+ {
+ // All other hosts should use their actual hostname
+ return m_gdb_client.LaunchGDBserverAndGetPort (pid, NULL);
+ }
+}
+
+bool
+PlatformRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid)
+{
+ return m_gdb_client.KillSpawnedProcess (pid);
}
lldb::ProcessSP
-PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
+PlatformRemoteGDBServer::Attach (ProcessAttachInfo &attach_info,
Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new target, else use existing one
Error &error)
@@ -632,22 +682,8 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
if (IsConnected())
{
lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
- ArchSpec remote_arch = GetRemoteSystemArchitecture();
- llvm::Triple &remote_triple = remote_arch.GetTriple();
- uint16_t port = 0;
- if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS)
- {
- // 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, "127.0.0.1");
- }
- else
- {
- // All other hosts should use their actual hostname
- port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL);
- }
-
+ uint16_t port = LaunchGDBserverAndGetPort(debugserver_pid);
+
if (port == 0)
{
error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
@@ -679,17 +715,9 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
if (process_sp)
{
- char connect_url[256];
- const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
- const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
- int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
- const int connect_url_len = ::snprintf (connect_url,
- sizeof(connect_url),
- "connect://%s:%u",
- override_hostname ? override_hostname : m_platform_hostname.c_str(),
- port + port_offset);
- assert (connect_url_len < (int)sizeof(connect_url));
- error = process_sp->ConnectRemote(nullptr, connect_url);
+ std::string connect_url =
+ MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port);
+ error = process_sp->ConnectRemote(nullptr, connect_url.c_str());
if (error.Success())
{
auto listener = attach_info.GetHijackListener();
@@ -700,7 +728,7 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
if (error.Fail() && debugserver_pid != LLDB_INVALID_PROCESS_ID)
{
- m_gdb_client.KillSpawnedProcess(debugserver_pid);
+ KillSpawnedProcess(debugserver_pid);
}
}
}
@@ -715,39 +743,44 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
}
Error
-PlatformRemoteGDBServer::MakeDirectory (const char *path, uint32_t mode)
+PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec, uint32_t mode)
{
- Error error = m_gdb_client.MakeDirectory(path,mode);
+ Error error = m_gdb_client.MakeDirectory(file_spec, mode);
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
- log->Printf ("PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) error = %u (%s)", path, mode, error.GetError(), error.AsCString());
+ log->Printf ("PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) error = %u (%s)",
+ file_spec.GetCString(), mode, error.GetError(), error.AsCString());
return error;
}
Error
-PlatformRemoteGDBServer::GetFilePermissions (const char *path, uint32_t &file_permissions)
+PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions)
{
- Error error = m_gdb_client.GetFilePermissions(path, file_permissions);
+ Error error = m_gdb_client.GetFilePermissions(file_spec, file_permissions);
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
- log->Printf ("PlatformRemoteGDBServer::GetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)", path, file_permissions, error.GetError(), error.AsCString());
+ log->Printf ("PlatformRemoteGDBServer::GetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)",
+ file_spec.GetCString(), file_permissions, error.GetError(), error.AsCString());
return error;
}
Error
-PlatformRemoteGDBServer::SetFilePermissions (const char *path, uint32_t file_permissions)
+PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions)
{
- Error error = m_gdb_client.SetFilePermissions(path, file_permissions);
+ Error error = m_gdb_client.SetFilePermissions(file_spec, file_permissions);
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
- log->Printf ("PlatformRemoteGDBServer::SetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)", path, file_permissions, error.GetError(), error.AsCString());
+ log->Printf ("PlatformRemoteGDBServer::SetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)",
+ file_spec.GetCString(), file_permissions, error.GetError(), error.AsCString());
return error;
}
lldb::user_id_t
-PlatformRemoteGDBServer::OpenFile (const lldb_private::FileSpec& file_spec,
+PlatformRemoteGDBServer::OpenFile (const FileSpec& file_spec,
uint32_t flags,
uint32_t mode,
Error &error)
@@ -762,7 +795,7 @@ PlatformRemoteGDBServer::CloseFile (lldb::user_id_t fd, Error &error)
}
lldb::user_id_t
-PlatformRemoteGDBServer::GetFileSize (const lldb_private::FileSpec& file_spec)
+PlatformRemoteGDBServer::GetFileSize (const FileSpec& file_spec)
{
return m_gdb_client.GetFileSize(file_spec);
}
@@ -787,9 +820,9 @@ PlatformRemoteGDBServer::WriteFile (lldb::user_id_t fd,
return m_gdb_client.WriteFile (fd, offset, src, src_len, error);
}
-lldb_private::Error
-PlatformRemoteGDBServer::PutFile (const lldb_private::FileSpec& source,
- const lldb_private::FileSpec& destination,
+Error
+PlatformRemoteGDBServer::PutFile (const FileSpec& source,
+ const FileSpec& destination,
uint32_t uid,
uint32_t gid)
{
@@ -797,45 +830,47 @@ PlatformRemoteGDBServer::PutFile (const lldb_private::FileSpec& source,
}
Error
-PlatformRemoteGDBServer::CreateSymlink (const char *src, // The name of the link is in src
- const char *dst) // The symlink points to dst
+PlatformRemoteGDBServer::CreateSymlink(const FileSpec &src, // The name of the link is in src
+ const FileSpec &dst) // The symlink points to dst
{
- Error error = m_gdb_client.CreateSymlink (src, dst);
+ Error error = m_gdb_client.CreateSymlink(src, dst);
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
- log->Printf ("PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') error = %u (%s)", src, dst, error.GetError(), error.AsCString());
+ log->Printf ("PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') error = %u (%s)",
+ src.GetCString(), dst.GetCString(), error.GetError(), error.AsCString());
return error;
}
Error
-PlatformRemoteGDBServer::Unlink (const char *path)
+PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec)
{
- Error error = m_gdb_client.Unlink (path);
+ Error error = m_gdb_client.Unlink(file_spec);
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
- log->Printf ("PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)", path, error.GetError(), error.AsCString());
+ log->Printf ("PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)",
+ file_spec.GetCString(), error.GetError(), error.AsCString());
return error;
}
bool
-PlatformRemoteGDBServer::GetFileExists (const lldb_private::FileSpec& file_spec)
+PlatformRemoteGDBServer::GetFileExists (const FileSpec& file_spec)
{
return m_gdb_client.GetFileExists (file_spec);
}
-lldb_private::Error
-PlatformRemoteGDBServer::RunShellCommand (const char *command, // Shouldn't be NULL
- const char *working_dir, // Pass NULL to use the current working directory
- int *status_ptr, // Pass NULL if you don't want the process exit status
- int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
- std::string *command_output, // Pass NULL if you don't want the command output
- uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
+Error
+PlatformRemoteGDBServer::RunShellCommand(const char *command, // Shouldn't be NULL
+ const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
{
- return m_gdb_client.RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+ return m_gdb_client.RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
}
void
PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames ()
{
m_trap_handlers.push_back (ConstString ("_sigtramp"));
-}
+}
diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
index a928c4695f79..1d97b4dbc683 100644
--- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
+++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
@@ -19,7 +19,10 @@
#include "lldb/Target/Platform.h"
#include "../../Process/gdb-remote/GDBRemoteCommunicationClient.h"
-class PlatformRemoteGDBServer : public lldb_private::Platform
+namespace lldb_private {
+namespace platform_gdb_server {
+
+class PlatformRemoteGDBServer : public Platform
{
public:
@@ -30,9 +33,9 @@ public:
Terminate ();
static lldb::PlatformSP
- CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+ CreateInstance (bool force, const ArchSpec *arch);
- static lldb_private::ConstString
+ static ConstString
GetPluginNameStatic();
static const char *
@@ -47,14 +50,14 @@ public:
//------------------------------------------------------------
// lldb_private::PluginInterface functions
//------------------------------------------------------------
- virtual lldb_private::ConstString
- GetPluginName()
+ ConstString
+ GetPluginName() override
{
return GetPluginNameStatic();
}
- virtual uint32_t
- GetPluginVersion()
+ uint32_t
+ GetPluginVersion() override
{
return 1;
}
@@ -63,163 +66,174 @@ public:
//------------------------------------------------------------
// lldb_private::Platform functions
//------------------------------------------------------------
- virtual lldb_private::Error
- ResolveExecutable (const lldb_private::ModuleSpec &module_spec,
+ Error
+ ResolveExecutable (const ModuleSpec &module_spec,
lldb::ModuleSP &module_sp,
- const lldb_private::FileSpecList *module_search_paths_ptr);
+ const FileSpecList *module_search_paths_ptr) override;
- virtual const char *
- GetDescription ();
+ bool
+ GetModuleSpec (const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec) override;
- virtual lldb_private::Error
- GetFileWithUUID (const lldb_private::FileSpec &platform_file,
- const lldb_private::UUID *uuid_ptr,
- lldb_private::FileSpec &local_file);
+ const char *
+ GetDescription () override;
- virtual bool
- GetProcessInfo (lldb::pid_t pid,
- lldb_private::ProcessInstanceInfo &proc_info);
+ Error
+ GetFileWithUUID (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file) override;
+
+ bool
+ GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info) override;
- virtual uint32_t
- FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
- lldb_private::ProcessInstanceInfoList &process_infos);
+ uint32_t
+ FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos) override;
- virtual lldb_private::Error
- LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info);
+ Error
+ LaunchProcess (ProcessLaunchInfo &launch_info) override;
- virtual lldb_private::Error
- KillProcess (const lldb::pid_t pid);
+ Error
+ KillProcess (const lldb::pid_t pid) override;
- virtual 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::Error &error);
+ lldb::ProcessSP
+ DebugProcess (ProcessLaunchInfo &launch_info,
+ Debugger &debugger,
+ Target *target, // Can be NULL, if NULL create a new target, else use existing one
+ Error &error) override;
- virtual lldb::ProcessSP
- Attach (lldb_private::ProcessAttachInfo &attach_info,
- lldb_private::Debugger &debugger,
- lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one
- lldb_private::Error &error);
+ lldb::ProcessSP
+ Attach (ProcessAttachInfo &attach_info,
+ Debugger &debugger,
+ Target *target, // Can be NULL, if NULL create a new target, else use existing one
+ Error &error) override;
- virtual bool
- GetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch);
+ bool
+ GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) override;
- virtual size_t
- GetSoftwareBreakpointTrapOpcode (lldb_private::Target &target,
- lldb_private::BreakpointSite *bp_site);
+ size_t
+ GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site) override;
- virtual bool
- GetRemoteOSVersion ();
+ bool
+ GetRemoteOSVersion () override;
- virtual bool
- GetRemoteOSBuildString (std::string &s);
+ bool
+ GetRemoteOSBuildString (std::string &s) override;
- virtual bool
- GetRemoteOSKernelDescription (std::string &s);
+ bool
+ GetRemoteOSKernelDescription (std::string &s) override;
// Remote Platform subclasses need to override this function
- virtual lldb_private::ArchSpec
- GetRemoteSystemArchitecture ();
+ ArchSpec
+ GetRemoteSystemArchitecture () override;
- virtual lldb_private::ConstString
- GetRemoteWorkingDirectory();
-
- virtual bool
- SetRemoteWorkingDirectory(const lldb_private::ConstString &path);
+ FileSpec
+ GetRemoteWorkingDirectory() override;
+ bool
+ SetRemoteWorkingDirectory(const FileSpec &working_dir) override;
// Remote subclasses should override this and return a valid instance
// name if connected.
- virtual const char *
- GetHostname ();
+ const char *
+ GetHostname () override;
- virtual const char *
- GetUserName (uint32_t uid);
+ const char *
+ GetUserName (uint32_t uid) override;
- virtual const char *
- GetGroupName (uint32_t gid);
+ const char *
+ GetGroupName (uint32_t gid) override;
- virtual bool
- IsConnected () const;
+ bool
+ IsConnected () const override;
- virtual lldb_private::Error
- ConnectRemote (lldb_private::Args& args);
+ Error
+ ConnectRemote (Args& args) override;
- virtual lldb_private::Error
- DisconnectRemote ();
-
- virtual lldb_private::Error
- MakeDirectory (const char *path, uint32_t file_permissions);
-
- virtual lldb_private::Error
- GetFilePermissions (const char *path, uint32_t &file_permissions);
-
- virtual lldb_private::Error
- SetFilePermissions (const char *path, uint32_t file_permissions);
+ Error
+ DisconnectRemote () override;
+ Error
+ MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions) override;
+
+ Error
+ GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions) override;
- virtual lldb::user_id_t
- OpenFile (const lldb_private::FileSpec& file_spec,
- uint32_t flags,
- uint32_t mode,
- lldb_private::Error &error);
+ Error
+ SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions) override;
+
+
+ lldb::user_id_t
+ OpenFile (const FileSpec& file_spec, uint32_t flags, uint32_t mode, Error &error) override;
- virtual bool
- CloseFile (lldb::user_id_t fd,
- lldb_private::Error &error);
+ bool
+ CloseFile (lldb::user_id_t fd, Error &error) override;
- virtual uint64_t
+ uint64_t
ReadFile (lldb::user_id_t fd,
uint64_t offset,
void *data_ptr,
uint64_t len,
- lldb_private::Error &error);
+ Error &error) override;
- virtual uint64_t
+ uint64_t
WriteFile (lldb::user_id_t fd,
uint64_t offset,
const void* data,
uint64_t len,
- lldb_private::Error &error);
+ Error &error) override;
- virtual lldb::user_id_t
- GetFileSize (const lldb_private::FileSpec& file_spec);
+ lldb::user_id_t
+ GetFileSize (const FileSpec& file_spec) override;
- virtual lldb_private::Error
- PutFile (const lldb_private::FileSpec& source,
- const lldb_private::FileSpec& destination,
+ Error
+ PutFile (const FileSpec& source,
+ const FileSpec& destination,
uint32_t uid = UINT32_MAX,
- uint32_t gid = UINT32_MAX);
+ uint32_t gid = UINT32_MAX) override;
- virtual lldb_private::Error
- CreateSymlink (const char *src, const char *dst);
+ Error
+ CreateSymlink(const FileSpec &src, const FileSpec &dst) override;
- virtual bool
- GetFileExists (const lldb_private::FileSpec& file_spec);
+ bool
+ GetFileExists (const FileSpec& file_spec) override;
- virtual lldb_private::Error
- Unlink (const char *path);
+ Error
+ Unlink(const FileSpec &path) 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
- int *status_ptr, // Pass NULL if you don't want the process exit status
- int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
- std::string *command_output, // Pass NULL if you don't want the command output
- uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish
+ Error
+ RunShellCommand(const char *command, // Shouldn't be NULL
+ const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec) override; // Timeout in seconds to wait for shell program to finish
- virtual void
- CalculateTrapHandlerSymbolNames ();
+ void
+ CalculateTrapHandlerSymbolNames () override;
protected:
- GDBRemoteCommunicationClient m_gdb_client;
+ process_gdb_remote::GDBRemoteCommunicationClient m_gdb_client;
std::string m_platform_description; // After we connect we can get a more complete description of what we are connected to
+ std::string m_platform_scheme;
std::string m_platform_hostname;
+ // Launch the lldb-gdbserver on the remote host and return the port it is listening on or 0 on
+ // failure. Subclasses should override this method if they want to do extra actions before or
+ // after launching the lldb-gdbserver.
+ virtual uint16_t
+ LaunchGDBserverAndGetPort (lldb::pid_t &pid);
+
+ virtual bool
+ KillSpawnedProcess (lldb::pid_t pid);
+
private:
DISALLOW_COPY_AND_ASSIGN (PlatformRemoteGDBServer);
};
+} // namespace platform_gdb_server
+} // namespace lldb_private
+
#endif // liblldb_PlatformRemoteGDBServer_h_
diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp
index 493f36ca8b48..cce7a1ef28c1 100644
--- a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp
+++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp
@@ -11,6 +11,7 @@
// C++ Includes
// Other libraries and framework includes
#include "lldb/Core/State.h"
+#include "lldb/Target/UnixSignals.h"
// Project includes
#include "FreeBSDThread.h"
diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.cpp b/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp
index 3b8cea737bcb..3b8cea737bcb 100644
--- a/source/Plugins/Process/POSIX/POSIXStopInfo.cpp
+++ b/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp
diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.h b/source/Plugins/Process/FreeBSD/POSIXStopInfo.h
index a1ee2ea68524..a1ee2ea68524 100644
--- a/source/Plugins/Process/POSIX/POSIXStopInfo.h
+++ b/source/Plugins/Process/FreeBSD/POSIXStopInfo.h
diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/FreeBSD/POSIXThread.cpp
index 1057585e1b2a..854796fb7448 100644
--- a/source/Plugins/Process/POSIX/POSIXThread.cpp
+++ b/source/Plugins/Process/FreeBSD/POSIXThread.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
#include <errno.h>
@@ -31,14 +29,13 @@
#include "POSIXThread.h"
#include "ProcessPOSIX.h"
#include "ProcessPOSIXLog.h"
-#include "Plugins/Process/Linux/ProcessMonitor.h"
+#include "ProcessMonitor.h"
+#include "RegisterContextPOSIXProcessMonitor_arm.h"
#include "RegisterContextPOSIXProcessMonitor_arm64.h"
#include "RegisterContextPOSIXProcessMonitor_mips64.h"
#include "RegisterContextPOSIXProcessMonitor_powerpc.h"
#include "RegisterContextPOSIXProcessMonitor_x86.h"
-#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
-#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
-#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
@@ -98,7 +95,6 @@ POSIXThread::GetMonitor()
return process.GetMonitor();
}
-// Overridden by FreeBSDThread; this is used only on Linux.
void
POSIXThread::RefreshStateAfterStop()
{
@@ -115,11 +111,6 @@ POSIXThread::RefreshStateAfterStop()
const bool force = false;
GetRegisterContext()->InvalidateIfNeeded (force);
}
- // FIXME: This should probably happen somewhere else.
- 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());
}
const char *
@@ -169,6 +160,9 @@ POSIXThread::GetRegisterContext()
case llvm::Triple::FreeBSD:
switch (target_arch.GetMachine())
{
+ case llvm::Triple::arm:
+ reg_interface = new RegisterContextFreeBSD_arm(target_arch);
+ break;
case llvm::Triple::ppc:
#ifndef __powerpc64__
reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch);
@@ -191,32 +185,6 @@ POSIXThread::GetRegisterContext()
}
break;
- case llvm::Triple::Linux:
- switch (target_arch.GetMachine())
- {
- 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::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:
- break;
- }
-
default:
break;
}
@@ -232,6 +200,13 @@ POSIXThread::GetRegisterContext()
m_reg_context_sp.reset(reg_ctx);
break;
}
+ case llvm::Triple::arm:
+ {
+ RegisterContextPOSIXProcessMonitor_arm *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm(*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);
@@ -313,18 +288,6 @@ POSIXThread::GetUnwinder()
return m_unwinder_ap.get();
}
-// Overridden by FreeBSDThread; this is used only on Linux.
-void
-POSIXThread::WillResume(lldb::StateType resume_state)
-{
- Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
- if (log)
- log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to %s", __FUNCTION__, GetID(), StateAsCString(resume_state));
- // TODO: the line below shouldn't really be done, but
- // the POSIXThread might rely on this so I will leave this in for now
- SetResumeState(resume_state);
-}
-
void
POSIXThread::DidStop()
{
@@ -512,7 +475,10 @@ POSIXThread::BreakNotify(const ProcessMessage &message)
if (bp_site)
{
lldb::break_id_t bp_id = bp_site->GetID();
- if (bp_site->ValidForThisThread(this))
+ // If we have an operating system plug-in, we might have set a thread specific breakpoint using the
+ // operating system thread ID, so we can't make any assumptions about the thread ID so we must always
+ // report the breakpoint regardless of the thread.
+ if (bp_site->ValidForThisThread(this) || GetProcess()->GetOperatingSystem () != NULL)
SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id));
else
{
@@ -641,6 +607,7 @@ POSIXThread::GetRegisterIndexFromOffset(unsigned offset)
break;
case llvm::Triple::aarch64:
+ case llvm::Triple::arm:
case llvm::Triple::mips64:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
@@ -674,6 +641,7 @@ POSIXThread::GetRegisterName(unsigned reg)
break;
case llvm::Triple::aarch64:
+ case llvm::Triple::arm:
case llvm::Triple::mips64:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
diff --git a/source/Plugins/Process/POSIX/POSIXThread.h b/source/Plugins/Process/FreeBSD/POSIXThread.h
index 56dcccbfb0f9..c38d194dbd19 100644
--- a/source/Plugins/Process/POSIX/POSIXThread.h
+++ b/source/Plugins/Process/FreeBSD/POSIXThread.h
@@ -35,32 +35,29 @@ public:
virtual ~POSIXThread();
void
- RefreshStateAfterStop();
-
- virtual void
- WillResume(lldb::StateType resume_state);
+ RefreshStateAfterStop() override;
// This notifies the thread when a private stop occurs.
- virtual void
- DidStop ();
+ void
+ DidStop () override;
const char *
- GetInfo();
+ GetInfo() override;
void
- SetName (const char *name);
+ SetName (const char *name) override;
const char *
- GetName ();
+ GetName () override;
- virtual lldb::RegisterContextSP
- GetRegisterContext();
+ lldb::RegisterContextSP
+ GetRegisterContext() override;
- virtual lldb::RegisterContextSP
- CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame) override;
- virtual lldb::addr_t
- GetThreadPointer ();
+ lldb::addr_t
+ GetThreadPointer () override;
//--------------------------------------------------------------------------
// These functions provide a mapping from the register offset
@@ -114,8 +111,8 @@ protected:
ProcessMonitor &
GetMonitor();
- virtual bool
- CalculateStopInfo();
+ bool
+ CalculateStopInfo() override;
void BreakNotify(const ProcessMessage &message);
void WatchNotify(const ProcessMessage &message);
@@ -129,7 +126,7 @@ protected:
void ExecNotify(const ProcessMessage &message);
lldb_private::Unwind *
- GetUnwinder();
+ GetUnwinder() override;
};
#endif // #ifndef liblldb_POSIXThread_H_
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
index 5a0b5ed14194..a0458f16e558 100644
--- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
+++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -11,6 +11,8 @@
#include <errno.h>
// C++ Includes
+#include <mutex>
+
// Other libraries and framework includes
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
@@ -56,23 +58,14 @@ ProcessFreeBSD::CreateInstance(Target& target,
void
ProcessFreeBSD::Initialize()
{
- static bool g_initialized = false;
+ static std::once_flag g_once_flag;
- if (!g_initialized)
- {
+ std::call_once(g_once_flag, []() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(),
CreateInstance);
- Log::Callbacks log_callbacks = {
- ProcessPOSIXLog::DisableLog,
- ProcessPOSIXLog::EnableLog,
- ProcessPOSIXLog::ListLogCategories
- };
-
- Log::RegisterLogChannel (ProcessFreeBSD::GetPluginNameStatic(), log_callbacks);
- ProcessPOSIXLog::RegisterPluginName(GetPluginNameStatic());
- g_initialized = true;
- }
+ ProcessPOSIXLog::Initialize(GetPluginNameStatic());
+ });
}
lldb_private::ConstString
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
index b33f83303971..28bca0916148 100644
--- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -28,6 +28,7 @@
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/PseudoTerminal.h"
#include "Plugins/Process/POSIX/CrashReason.h"
@@ -107,13 +108,9 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data,
if (req == PT_GETREGS) {
struct reg *r = (struct reg *) addr;
- log->Printf("PT_GETREGS: ip=0x%lx", r->r_rip);
- log->Printf("PT_GETREGS: sp=0x%lx", r->r_rsp);
- log->Printf("PT_GETREGS: bp=0x%lx", r->r_rbp);
- log->Printf("PT_GETREGS: ax=0x%lx", r->r_rax);
+ log->Printf("PT_GETREGS: rip=0x%lx rsp=0x%lx rbp=0x%lx rax=0x%lx",
+ r->r_rip, r->r_rsp, r->r_rbp, r->r_rax);
}
-#endif
-#ifndef __powerpc__
if (req == PT_GETDBREGS || req == PT_SETDBREGS) {
struct dbreg *r = (struct dbreg *) addr;
char setget = (req == PT_GETDBREGS) ? 'G' : 'S';
@@ -772,17 +769,17 @@ ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor,
lldb_private::Module *module,
char const **argv,
char const **envp,
- const char *stdin_path,
- const char *stdout_path,
- const char *stderr_path,
- const char *working_dir)
+ const FileSpec &stdin_file_spec,
+ const FileSpec &stdout_file_spec,
+ const FileSpec &stderr_file_spec,
+ const FileSpec &working_dir)
: OperationArgs(monitor),
m_module(module),
m_argv(argv),
m_envp(envp),
- m_stdin_path(stdin_path),
- m_stdout_path(stdout_path),
- m_stderr_path(stderr_path),
+ m_stdin_file_spec(stdin_file_spec),
+ m_stdout_file_spec(stdout_file_spec),
+ m_stderr_file_spec(stderr_file_spec),
m_working_dir(working_dir) { }
ProcessMonitor::LaunchArgs::~LaunchArgs()
@@ -811,10 +808,10 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
Module *module,
const char *argv[],
const char *envp[],
- const char *stdin_path,
- const char *stdout_path,
- const char *stderr_path,
- const char *working_dir,
+ const FileSpec &stdin_file_spec,
+ const FileSpec &stdout_file_spec,
+ const FileSpec &stderr_file_spec,
+ const FileSpec &working_dir,
const lldb_private::ProcessLaunchInfo & /* launch_info */,
lldb_private::Error &error)
: m_process(static_cast<ProcessFreeBSD *>(process)),
@@ -823,8 +820,10 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
m_operation(0)
{
std::unique_ptr<LaunchArgs> args(new LaunchArgs(this, module, argv, envp,
- stdin_path, stdout_path, stderr_path,
- working_dir));
+ stdin_file_spec,
+ stdout_file_spec,
+ stderr_file_spec,
+ working_dir));
sem_init(&m_operation_pending, 0, 0);
@@ -955,15 +954,15 @@ ProcessMonitor::Launch(LaunchArgs *args)
ProcessFreeBSD &process = monitor->GetProcess();
const char **argv = args->m_argv;
const char **envp = args->m_envp;
- const char *stdin_path = args->m_stdin_path;
- const char *stdout_path = args->m_stdout_path;
- const char *stderr_path = args->m_stderr_path;
- const char *working_dir = args->m_working_dir;
+ const FileSpec &stdin_file_spec = args->m_stdin_file_spec;
+ const FileSpec &stdout_file_spec = args->m_stdout_file_spec;
+ const FileSpec &stderr_file_spec = args->m_stderr_file_spec;
+ const FileSpec &working_dir = args->m_working_dir;
lldb_utility::PseudoTerminal terminal;
const size_t err_len = 1024;
char err_str[err_len];
- lldb::pid_t pid;
+ ::pid_t pid;
// Propagate the environment if one is not supplied.
if (envp == NULL || envp[0] == NULL)
@@ -1010,22 +1009,21 @@ ProcessMonitor::Launch(LaunchArgs *args)
//
// FIXME: If two or more of the paths are the same we needlessly open
// the same file multiple times.
- if (stdin_path != NULL && stdin_path[0])
- if (!DupDescriptor(stdin_path, STDIN_FILENO, O_RDONLY))
+ if (stdin_file_spec)
+ if (!DupDescriptor(stdin_file_spec, STDIN_FILENO, O_RDONLY))
exit(eDupStdinFailed);
- if (stdout_path != NULL && stdout_path[0])
- if (!DupDescriptor(stdout_path, STDOUT_FILENO, O_WRONLY | O_CREAT))
+ if (stdout_file_spec)
+ if (!DupDescriptor(stdout_file_spec, STDOUT_FILENO, O_WRONLY | O_CREAT))
exit(eDupStdoutFailed);
- if (stderr_path != NULL && stderr_path[0])
- if (!DupDescriptor(stderr_path, STDERR_FILENO, O_WRONLY | O_CREAT))
+ if (stderr_file_spec)
+ if (!DupDescriptor(stderr_file_spec, STDERR_FILENO, O_WRONLY | O_CREAT))
exit(eDupStderrFailed);
// Change working directory
- if (working_dir != NULL && working_dir[0])
- if (0 != ::chdir(working_dir))
- exit(eChdirFailed);
+ if (working_dir && 0 != ::chdir(working_dir.GetCString()))
+ exit(eChdirFailed);
// Execute. We should never return.
execve(argv[0],
@@ -1556,9 +1554,9 @@ ProcessMonitor::Detach(lldb::tid_t tid)
}
bool
-ProcessMonitor::DupDescriptor(const char *path, int fd, int flags)
+ProcessMonitor::DupDescriptor(const FileSpec &file_spec, int fd, int flags)
{
- int target_fd = open(path, flags, 0666);
+ int target_fd = open(file_spec.GetCString(), flags, 0666);
if (target_fd == -1)
return false;
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
index 4ae963c89a2f..20ce582d973e 100644
--- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
@@ -17,6 +17,7 @@
// C++ Includes
// Other libraries and framework includes
#include "lldb/lldb-types.h"
+#include "lldb/Host/FileSpec.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/Mutex.h"
@@ -52,10 +53,10 @@ public:
lldb_private::Module *module,
char const *argv[],
char const *envp[],
- const char *stdin_path,
- const char *stdout_path,
- const char *stderr_path,
- const char *working_dir,
+ const lldb_private::FileSpec &stdin_file_spec,
+ const lldb_private::FileSpec &stdout_file_spec,
+ const lldb_private::FileSpec &stderr_file_spec,
+ const lldb_private::FileSpec &working_dir,
const lldb_private::ProcessLaunchInfo &launch_info,
lldb_private::Error &error);
@@ -228,7 +229,7 @@ private:
// the operation is complete.
sem_t m_operation_pending;
sem_t m_operation_done;
-
+
struct OperationArgs
{
OperationArgs(ProcessMonitor *monitor);
@@ -250,20 +251,20 @@ private:
lldb_private::Module *module,
char const **argv,
char const **envp,
- const char *stdin_path,
- const char *stdout_path,
- const char *stderr_path,
- const char *working_dir);
+ const lldb_private::FileSpec &stdin_file_spec,
+ const lldb_private::FileSpec &stdout_file_spec,
+ const lldb_private::FileSpec &stderr_file_spec,
+ const lldb_private::FileSpec &working_dir);
~LaunchArgs();
- lldb_private::Module *m_module; // The executable image to launch.
- char const **m_argv; // Process arguments.
- char const **m_envp; // Process environment.
- const char *m_stdin_path; // Redirect stdin or NULL.
- const char *m_stdout_path; // Redirect stdout or NULL.
- const char *m_stderr_path; // Redirect stderr or NULL.
- const char *m_working_dir; // Working directory or NULL.
+ lldb_private::Module *m_module; // The executable image to launch.
+ char const **m_argv; // Process arguments.
+ char const **m_envp; // Process environment.
+ const lldb_private::FileSpec m_stdin_file_spec; // Redirect stdin or empty.
+ const lldb_private::FileSpec m_stdout_file_spec; // Redirect stdout or empty.
+ const lldb_private::FileSpec m_stderr_file_spec; // Redirect stderr or empty.
+ const lldb_private::FileSpec m_working_dir; // Working directory or empty.
};
void
@@ -298,7 +299,7 @@ private:
ServeOperation(OperationArgs *args);
static bool
- DupDescriptor(const char *path, int fd, int flags);
+ DupDescriptor(const lldb_private::FileSpec &file_spec, int fd, int flags);
static bool
MonitorCallback(void *callback_baton,
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp
index 882fac75c9a0..360382e2e63a 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp
@@ -7,13 +7,12 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
#include <errno.h>
// C++ Includes
// Other libraries and framework includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
@@ -29,46 +28,15 @@
#include "ProcessPOSIX.h"
#include "ProcessPOSIXLog.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
-#include "Plugins/Process/Linux/ProcessMonitor.h"
#include "POSIXThread.h"
+#include "ProcessMonitor.h"
+
+#include "lldb/Host/posix/Fcntl.h"
using namespace lldb;
using namespace lldb_private;
//------------------------------------------------------------------------------
-// Static functions.
-#if 0
-Process*
-ProcessPOSIX::CreateInstance(Target& target, Listener &listener)
-{
- return new ProcessPOSIX(target, listener);
-}
-
-
-void
-ProcessPOSIX::Initialize()
-{
- static bool g_initialized = false;
-
- if (!g_initialized)
- {
- g_initialized = true;
- PluginManager::RegisterPlugin(GetPluginNameStatic(),
- GetPluginDescriptionStatic(),
- CreateInstance);
-
- Log::Callbacks log_callbacks = {
- ProcessPOSIXLog::DisableLog,
- ProcessPOSIXLog::EnableLog,
- ProcessPOSIXLog::ListLogCategories
- };
-
- Log::RegisterLogChannel (ProcessPOSIX::GetPluginNameStatic(), log_callbacks);
- }
-}
-#endif
-
-//------------------------------------------------------------------------------
// Constructors and destructors.
ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener, UnixSignalsSP &unix_signals_sp)
@@ -82,9 +50,9 @@ ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener, UnixSignalsSP &un
{
// FIXME: Putting this code in the ctor and saving the byte order in a
// member variable is a hack to avoid const qual issues in GetByteOrder.
- lldb::ModuleSP module = GetTarget().GetExecutableModule();
- if (module && module->GetObjectFile())
- m_byte_order = module->GetObjectFile()->GetByteOrder();
+ lldb::ModuleSP module = GetTarget().GetExecutableModule();
+ if (module && module->GetObjectFile())
+ m_byte_order = module->GetObjectFile()->GetByteOrder();
}
ProcessPOSIX::~ProcessPOSIX()
@@ -115,7 +83,7 @@ ProcessPOSIX::CanDebug(Target &target, bool plugin_specified_by_name)
}
Error
-ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid)
+ProcessPOSIX::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info)
{
Error error;
assert(m_monitor == NULL);
@@ -164,39 +132,30 @@ ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid)
}
Error
-ProcessPOSIX::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info)
-{
- return DoAttachToProcessWithID(pid);
-}
-
-Error
ProcessPOSIX::WillLaunch(Module* module)
{
Error error;
return error;
}
-const char *
-ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const char *default_path,
- const char *dbg_pts_path)
+FileSpec
+ProcessPOSIX::GetFileSpec(const lldb_private::FileAction *file_action,
+ const FileSpec &default_file_spec,
+ const FileSpec &dbg_pts_file_spec)
{
- const char *path = NULL;
+ FileSpec file_spec{};
- if (file_action)
+ if (file_action && file_action->GetAction() == 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 (!path || (dbg_pts_path &&
- ::strncmp(path, dbg_pts_path, ::strlen(dbg_pts_path)) == 0))
- path = default_path;
- }
+ file_spec = file_action->GetFileSpec();
+ // 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 (!file_spec || file_spec == dbg_pts_file_spec)
+ file_spec = default_file_spec;
}
- return path;
+ return file_spec;
}
Error
@@ -206,46 +165,46 @@ ProcessPOSIX::DoLaunch (Module *module,
Error error;
assert(m_monitor == NULL);
- const char* working_dir = launch_info.GetWorkingDirectory();
- if (working_dir) {
- FileSpec WorkingDir(working_dir, true);
- if (!WorkingDir || WorkingDir.GetFileType() != FileSpec::eFileTypeDirectory)
- {
- error.SetErrorStringWithFormat("No such file or directory: %s", working_dir);
- return error;
- }
+ FileSpec working_dir = launch_info.GetWorkingDirectory();
+ if (working_dir &&
+ (!working_dir.ResolvePath() ||
+ working_dir.GetFileType() != FileSpec::eFileTypeDirectory))
+ {
+ error.SetErrorStringWithFormat("No such file or directory: %s",
+ working_dir.GetCString());
+ return error;
}
SetPrivateState(eStateLaunching);
const lldb_private::FileAction *file_action;
- // Default of NULL will mean to use existing open file descriptors
- const char *stdin_path = NULL;
- const char *stdout_path = NULL;
- const char *stderr_path = NULL;
+ // Default of empty will mean to use existing open file descriptors
+ FileSpec stdin_file_spec{};
+ FileSpec stdout_file_spec{};
+ FileSpec stderr_file_spec{};
- const char * dbg_pts_path = launch_info.GetPTY().GetSlaveName(NULL,0);
+ const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL,0), false};
file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
- stdin_path = GetFilePath(file_action, stdin_path, dbg_pts_path);
+ stdin_file_spec = GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec);
file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
- stdout_path = GetFilePath(file_action, stdout_path, dbg_pts_path);
+ stdout_file_spec = GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec);
file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
- stderr_path = GetFilePath(file_action, stderr_path, dbg_pts_path);
-
- m_monitor = new ProcessMonitor (this,
- module,
- launch_info.GetArguments().GetConstArgumentVector(),
- launch_info.GetEnvironmentEntries().GetConstArgumentVector(),
- stdin_path,
- stdout_path,
- stderr_path,
- working_dir,
- launch_info,
- error);
+ stderr_file_spec = GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec);
+
+ m_monitor = new ProcessMonitor(this,
+ module,
+ launch_info.GetArguments().GetConstArgumentVector(),
+ launch_info.GetEnvironmentEntries().GetConstArgumentVector(),
+ stdin_file_spec,
+ stdout_file_spec,
+ stderr_file_spec,
+ working_dir,
+ launch_info,
+ error);
m_module = module;
@@ -426,13 +385,11 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message)
}
else
{
- StopAllThreads(message.GetTID());
SetPrivateState(eStateStopped);
}
}
else
{
- StopAllThreads(message.GetTID());
SetPrivateState(eStateStopped);
}
break;
@@ -468,7 +425,6 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message)
case ProcessMessage::eCrashMessage:
assert(thread);
thread->SetState(eStateStopped);
- StopAllThreads(message.GetTID());
SetPrivateState(eStateStopped);
break;
@@ -481,7 +437,6 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message)
}
assert(thread);
thread->SetState(eStateStopped);
- StopAllThreads(message.GetTID());
SetPrivateState(eStateStopped);
break;
}
@@ -490,7 +445,6 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message)
{
assert(thread);
thread->SetState(eStateStopped);
- StopAllThreads(message.GetTID());
SetPrivateState(eStateStopped);
break;
}
@@ -500,12 +454,6 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message)
m_message_queue.push(message);
}
-void
-ProcessPOSIX::StopAllThreads(lldb::tid_t stop_tid)
-{
- // FIXME: Will this work the same way on FreeBSD and Linux?
-}
-
bool
ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid)
{
@@ -671,6 +619,33 @@ ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
assert(false && "CPU type not supported!");
break;
+ case llvm::Triple::arm:
+ {
+ // The ARM reference recommends the use of 0xe7fddefe and 0xdefe
+ // but the linux kernel does otherwise.
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 };
+ static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde };
+
+ lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0));
+ AddressClass addr_class = eAddressClassUnknown;
+
+ if (bp_loc_sp)
+ addr_class = bp_loc_sp->GetAddress ().GetAddressClass ();
+
+ if (addr_class == eAddressClassCodeAlternateISA
+ || (addr_class == eAddressClassUnknown
+ && bp_loc_sp->GetAddress().GetOffset() & 1))
+ {
+ opcode = g_thumb_breakpoint_opcode;
+ opcode_size = sizeof(g_thumb_breakpoint_opcode);
+ }
+ else
+ {
+ opcode = g_arm_breakpoint_opcode;
+ opcode_size = sizeof(g_arm_breakpoint_opcode);
+ }
+ }
+ break;
case llvm::Triple::aarch64:
opcode = g_aarch64_opcode;
opcode_size = sizeof(g_aarch64_opcode);
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/FreeBSD/ProcessPOSIX.h
index f152356b3093..70694cb9b193 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.h
+++ b/source/Plugins/Process/FreeBSD/ProcessPOSIX.h
@@ -41,104 +41,101 @@ public:
//------------------------------------------------------------------
// Process protocol.
//------------------------------------------------------------------
- virtual void
+ void
Finalize() override;
- virtual bool
+ bool
CanDebug(lldb_private::Target &target, bool plugin_specified_by_name) override;
- virtual lldb_private::Error
+ lldb_private::Error
WillLaunch(lldb_private::Module *module) override;
- virtual lldb_private::Error
- DoAttachToProcessWithID(lldb::pid_t pid) override;
-
- virtual lldb_private::Error
+ lldb_private::Error
DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override;
- virtual lldb_private::Error
+ lldb_private::Error
DoLaunch (lldb_private::Module *exe_module,
lldb_private::ProcessLaunchInfo &launch_info) override;
- virtual void
+ void
DidLaunch() override;
- virtual lldb_private::Error
+ lldb_private::Error
DoResume() override;
- virtual lldb_private::Error
+ lldb_private::Error
DoHalt(bool &caused_stop) override;
- virtual lldb_private::Error
+ lldb_private::Error
DoDetach(bool keep_stopped) override = 0;
- virtual lldb_private::Error
+ lldb_private::Error
DoSignal(int signal) override;
- virtual lldb_private::Error
+ lldb_private::Error
DoDestroy() override;
- virtual void
+ void
DoDidExec() override;
- virtual void
+ void
RefreshStateAfterStop() override;
- virtual bool
+ bool
IsAlive() override;
- virtual size_t
+ size_t
DoReadMemory(lldb::addr_t vm_addr,
void *buf,
size_t size,
lldb_private::Error &error) override;
- virtual size_t
+ size_t
DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
lldb_private::Error &error) override;
- virtual lldb::addr_t
+ lldb::addr_t
DoAllocateMemory(size_t size, uint32_t permissions,
lldb_private::Error &error) override;
- virtual lldb_private::Error
+ lldb_private::Error
DoDeallocateMemory(lldb::addr_t ptr) override;
virtual size_t
GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site);
- virtual lldb_private::Error
+ lldb_private::Error
EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
- virtual lldb_private::Error
+ lldb_private::Error
DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
- virtual lldb_private::Error
+ lldb_private::Error
EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override;
- virtual lldb_private::Error
+ lldb_private::Error
DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override;
- virtual lldb_private::Error
+ lldb_private::Error
GetWatchpointSupportInfo(uint32_t &num) override;
- virtual lldb_private::Error
+ lldb_private::Error
GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
virtual uint32_t
UpdateThreadListIfNeeded();
- virtual bool
+ bool
UpdateThreadList(lldb_private::ThreadList &old_thread_list,
lldb_private::ThreadList &new_thread_list) override = 0;
virtual lldb::ByteOrder
GetByteOrder() const;
- virtual lldb::addr_t
+ lldb::addr_t
GetImageInfoAddress() override;
- virtual size_t
+ size_t
PutSTDIN(const char *buf, size_t len, lldb_private::Error &error) override;
const lldb::DataBufferSP
@@ -154,13 +151,10 @@ public:
ProcessMonitor &
GetMonitor() { assert(m_monitor); return *m_monitor; }
- const char *GetFilePath(const lldb_private::FileAction *file_action, const char *default_path,
- const char *dbg_pts_path);
-
- /// Stops all threads in the process.
- /// The \p stop_tid parameter indicates the thread which initiated the stop.
- virtual void
- StopAllThreads(lldb::tid_t stop_tid);
+ lldb_private::FileSpec
+ GetFileSpec(const lldb_private::FileAction *file_action,
+ const lldb_private::FileSpec &default_file_spec,
+ const lldb_private::FileSpec &dbg_pts_file_spec);
/// Adds the thread to the list of threads for which we have received the initial stopping signal.
/// The \p stop_tid parameter indicates the thread which the stop happened for.
diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp
new file mode 100644
index 000000000000..ac2f81d53929
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp
@@ -0,0 +1,322 @@
+//===-- RegisterContextPOSIXProcessMonitor_arm.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/DataBufferHeap.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+
+#include "RegisterContextPOSIX_arm.h"
+#include "ProcessPOSIX.h"
+#include "RegisterContextPOSIXProcessMonitor_arm.h"
+#include "ProcessMonitor.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+#define REG_CONTEXT_SIZE (GetGPRSize())
+
+RegisterContextPOSIXProcessMonitor_arm::RegisterContextPOSIXProcessMonitor_arm(Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info)
+ : RegisterContextPOSIX_arm(thread, concrete_frame_idx, register_info)
+{
+}
+
+ProcessMonitor &
+RegisterContextPOSIXProcessMonitor_arm::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ReadGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr));
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::WriteGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::WriteFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr));
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ unsigned reg_to_write = reg;
+ RegisterValue value_to_write = value;
+
+ // Check if this is a subregister of a full register.
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
+ {
+ RegisterValue full_value;
+ uint32_t full_reg = reg_info->invalidate_regs[0];
+ const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
+
+ // Read the full register.
+ if (ReadRegister(full_reg_info, full_value))
+ {
+ Error error;
+ ByteOrder byte_order = GetByteOrder();
+ uint8_t dst[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[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_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsFPR(reg))
+ {
+ if (!ReadFPR())
+ return false;
+ }
+ else
+ {
+ return ReadRegister(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_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsGPR(reg))
+ {
+ return WriteRegister(reg, value);
+ }
+ else if (IsFPR(reg))
+ {
+ return WriteFPR();
+ }
+
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ReadAllRegisterValues(DataBufferSP &data_sp)
+{
+ bool success = false;
+ data_sp.reset (new 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_arm, GetGPRSize());
+ dst += GetGPRSize();
+ ::memcpy (dst, &m_fpr, sizeof(m_fpr));
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::WriteAllRegisterValues(const 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_arm, src, GetGPRSize());
+
+ if (WriteGPR())
+ {
+ src += GetGPRSize();
+ ::memcpy (&m_fpr, src, sizeof(m_fpr));
+
+ success = WriteFPR();
+ }
+ }
+ }
+ return success;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpoint(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_arm::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::HardwareSingleStep(bool enable)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::UpdateAfterBreakpoint()
+{
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ return true;
+}
+
+unsigned
+RegisterContextPOSIXProcessMonitor_arm::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers_arm; reg++)
+ {
+ if (GetRegisterInfo()[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers_arm && "Invalid register offset.");
+ return reg;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::IsWatchpointHit(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ClearWatchpointHits()
+{
+ return false;
+}
+
+addr_t
+RegisterContextPOSIXProcessMonitor_arm::GetWatchpointAddress(uint32_t hw_index)
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::IsWatchpointVacant(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_arm::NumSupportedHardwareWatchpoints()
+{
+ return 0;
+}
+
diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h
new file mode 100644
index 000000000000..12a43c77837c
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h
@@ -0,0 +1,95 @@
+//===-- RegisterContextPOSIXProcessMonitor_arm.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_arm_H_
+#define liblldb_RegisterContextPOSIXProcessMonitor_arm_H_
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
+
+class RegisterContextPOSIXProcessMonitor_arm:
+ public RegisterContextPOSIX_arm,
+ public POSIXBreakpointProtocol
+{
+public:
+ RegisterContextPOSIXProcessMonitor_arm(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_arm64.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
index ec34d9e28161..d79def52499f 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp
+++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
@@ -7,16 +7,20 @@
//
//===---------------------------------------------------------------------===//
-#include "lldb/Target/Thread.h"
+#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
#include "ProcessPOSIX.h"
+#include "ProcessMonitor.h"
#include "RegisterContextPOSIXProcessMonitor_arm64.h"
-#include "Plugins/Process/Linux/ProcessMonitor.h"
#define REG_CONTEXT_SIZE (GetGPRSize())
+using namespace lldb;
+using namespace lldb_private;
+
RegisterContextPOSIXProcessMonitor_arm64::RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread,
uint32_t concrete_frame_idx,
lldb_private::RegisterInfoInterface *register_info)
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h
index eb24d4852ab8..eb24d4852ab8 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h
+++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp
index 6717d20da056..893a0f22b6f8 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp
+++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp
@@ -7,13 +7,14 @@
//
//===---------------------------------------------------------------------===//
-#include "lldb/Target/Thread.h"
+#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
#include "ProcessPOSIX.h"
+#include "ProcessMonitor.h"
#include "RegisterContextPOSIXProcessMonitor_mips64.h"
-#include "Plugins/Process/Linux/ProcessMonitor.h"
using namespace lldb_private;
using namespace lldb;
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h
index 79e4468b1adf..79e4468b1adf 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h
+++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp
index 80e1c1984225..8c12b62a202f 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp
+++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp
@@ -7,8 +7,9 @@
//
//===---------------------------------------------------------------------===//
-#include "lldb/Target/Thread.h"
+#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
#include "RegisterContextPOSIX_powerpc.h"
#include "ProcessPOSIX.h"
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h
index 5c686df4836f..5c686df4836f 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h
+++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp
index 1956e4584fa9..9245441f659f 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp
+++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp
@@ -7,16 +7,13 @@
//
//===---------------------------------------------------------------------===//
-#include "lldb/Target/Thread.h"
+#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
-#include "Plugins/Process/POSIX/ProcessPOSIX.h"
+#include "Plugins/Process/FreeBSD/ProcessPOSIX.h"
#include "RegisterContextPOSIXProcessMonitor_x86.h"
-#if defined(__FreeBSD__)
#include "Plugins/Process/FreeBSD/ProcessMonitor.h"
-#else
-#include "Plugins/Process/Linux/ProcessMonitor.h"
-#endif
using namespace lldb_private;
using namespace lldb;
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h
index 2afb195c4c36..2afb195c4c36 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h
+++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h
diff --git a/source/Plugins/Process/POSIX/CrashReason.cpp b/source/Plugins/Process/POSIX/CrashReason.cpp
index 4dd91a6f1de8..6de13f470c5e 100644
--- a/source/Plugins/Process/POSIX/CrashReason.cpp
+++ b/source/Plugins/Process/POSIX/CrashReason.cpp
@@ -134,69 +134,69 @@ GetCrashReasonString (CrashReason reason, lldb::addr_t fault_addr)
break;
case CrashReason::eInvalidAddress:
- str = "invalid address";
+ str = "signal SIGSEGV: invalid address";
AppendFaultAddr (str, fault_addr);
break;
case CrashReason::ePrivilegedAddress:
- str = "address access protected";
+ str = "signal SIGSEGV: address access protected";
AppendFaultAddr (str, fault_addr);
break;
case CrashReason::eIllegalOpcode:
- str = "illegal instruction";
+ str = "signal SIGILL: illegal instruction";
break;
case CrashReason::eIllegalOperand:
- str = "illegal instruction operand";
+ str = "signal SIGILL: illegal instruction operand";
break;
case CrashReason::eIllegalAddressingMode:
- str = "illegal addressing mode";
+ str = "signal SIGILL: illegal addressing mode";
break;
case CrashReason::eIllegalTrap:
- str = "illegal trap";
+ str = "signal SIGILL: illegal trap";
break;
case CrashReason::ePrivilegedOpcode:
- str = "privileged instruction";
+ str = "signal SIGILL: privileged instruction";
break;
case CrashReason::ePrivilegedRegister:
- str = "privileged register";
+ str = "signal SIGILL: privileged register";
break;
case CrashReason::eCoprocessorError:
- str = "coprocessor error";
+ str = "signal SIGILL: coprocessor error";
break;
case CrashReason::eInternalStackError:
- str = "internal stack error";
+ str = "signal SIGILL: internal stack error";
break;
case CrashReason::eIllegalAlignment:
- str = "illegal alignment";
+ str = "signal SIGBUS: illegal alignment";
break;
case CrashReason::eIllegalAddress:
- str = "illegal address";
+ str = "signal SIGBUS: illegal address";
break;
case CrashReason::eHardwareError:
- str = "hardware error";
+ str = "signal SIGBUS: hardware error";
break;
case CrashReason::eIntegerDivideByZero:
- str = "integer divide by zero";
+ str = "signal SIGFPE: integer divide by zero";
break;
case CrashReason::eIntegerOverflow:
- str = "integer overflow";
+ str = "signal SIGFPE: integer overflow";
break;
case CrashReason::eFloatDivideByZero:
- str = "floating point divide by zero";
+ str = "signal SIGFPE: floating point divide by zero";
break;
case CrashReason::eFloatOverflow:
- str = "floating point overflow";
+ str = "signal SIGFPE: floating point overflow";
break;
case CrashReason::eFloatUnderflow:
- str = "floating point underflow";
+ str = "signal SIGFPE: floating point underflow";
break;
case CrashReason::eFloatInexactResult:
- str = "inexact floating point result";
+ str = "signal SIGFPE: inexact floating point result";
break;
case CrashReason::eFloatInvalidOperation:
- str = "invalid floating point operation";
+ str = "signal SIGFPE: invalid floating point operation";
break;
case CrashReason::eFloatSubscriptRange:
- str = "invalid floating point subscript range";
+ str = "signal SIGFPE: invalid floating point subscript range";
break;
}
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp b/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
index 624ca87b883a..b259804a3a27 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
+++ b/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
@@ -9,10 +9,11 @@
#include "ProcessPOSIXLog.h"
+#include <mutex>
+
#include "lldb/Interpreter/Args.h"
#include "lldb/Core/StreamFile.h"
-#include "ProcessPOSIX.h"
#include "ProcessPOSIXLog.h"
using namespace lldb;
@@ -33,6 +34,22 @@ GetLog ()
return g_log;
}
+void
+ProcessPOSIXLog::Initialize(ConstString name)
+{
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, [name](){
+ Log::Callbacks log_callbacks = {
+ DisableLog,
+ EnableLog,
+ ListLogCategories
+ };
+
+ Log::RegisterLogChannel (name, log_callbacks);
+ RegisterPluginName(name);
+ });
+}
Log *
ProcessPOSIXLog::GetLogIfAllCategoriesSet (uint32_t mask)
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIXLog.h b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
index a1e2e3747d21..7edd839152e6 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
+++ b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
@@ -43,6 +43,12 @@ class ProcessPOSIXLog
static const char *m_pluginname;
public:
+ // ---------------------------------------------------------------------
+ // Public Static Methods
+ // ---------------------------------------------------------------------
+ static void
+ Initialize(lldb_private::ConstString name);
+
static void
RegisterPluginName(const char *pluginName)
{
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
index 25a195e11a03..4eff442c1a0d 100644
--- a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -7,22 +7,18 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "DynamicRegisterInfo.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/DataFormatters/FormatManager.h"
-
-#ifndef LLDB_DISABLE_PYTHON
-#include "lldb/Interpreter/PythonDataObjects.h"
-#endif
+#include "lldb/Host/StringConvert.h"
using namespace lldb;
using namespace lldb_private;
@@ -39,7 +35,8 @@ DynamicRegisterInfo::DynamicRegisterInfo () :
{
}
-DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary &dict, ByteOrder byte_order) :
+DynamicRegisterInfo::DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict,
+ const lldb_private::ArchSpec &arch) :
m_regs (),
m_sets (),
m_set_reg_nums (),
@@ -49,30 +46,27 @@ DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary &
m_reg_data_byte_size (0),
m_finalized (false)
{
- SetRegisterInfo (dict, byte_order);
+ SetRegisterInfo (dict, arch);
}
DynamicRegisterInfo::~DynamicRegisterInfo ()
{
}
-
size_t
-DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict,
- ByteOrder byte_order)
+DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, const ArchSpec &arch)
{
assert(!m_finalized);
-#ifndef LLDB_DISABLE_PYTHON
- PythonList sets (dict.GetItemForKey("sets"));
- if (sets)
+ StructuredData::Array *sets = nullptr;
+ if (dict.GetValueForKeyAsArray("sets", sets))
{
- const uint32_t num_sets = sets.GetSize();
+ const uint32_t num_sets = sets->GetSize();
for (uint32_t i=0; i<num_sets; ++i)
{
- PythonString py_set_name(sets.GetItemAtIndex(i));
+ std::string set_name_str;
ConstString set_name;
- if (py_set_name)
- set_name.SetCString(py_set_name.GetString());
+ if (sets->GetItemAtIndexAsString(i, set_name_str))
+ set_name.SetCString(set_name_str.c_str());
if (set_name)
{
RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
@@ -87,346 +81,312 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
}
m_set_reg_nums.resize(m_sets.size());
}
- PythonList regs (dict.GetItemForKey("registers"));
- if (regs)
- {
- const uint32_t num_regs = regs.GetSize();
- PythonString name_pystr("name");
- PythonString altname_pystr("alt-name");
- PythonString bitsize_pystr("bitsize");
- PythonString offset_pystr("offset");
- PythonString encoding_pystr("encoding");
- PythonString format_pystr("format");
- PythonString set_pystr("set");
- PythonString gcc_pystr("gcc");
- PythonString dwarf_pystr("dwarf");
- PythonString generic_pystr("generic");
- PythonString slice_pystr("slice");
- PythonString composite_pystr("composite");
- PythonString invalidate_regs_pystr("invalidate-regs");
-
+ StructuredData::Array *regs = nullptr;
+ if (!dict.GetValueForKeyAsArray("registers", regs))
+ return 0;
+
+ const uint32_t num_regs = regs->GetSize();
// typedef std::map<std::string, std::vector<std::string> > InvalidateNameMap;
// InvalidateNameMap invalidate_map;
- for (uint32_t i=0; i<num_regs; ++i)
+ for (uint32_t i = 0; i < num_regs; ++i)
+ {
+ StructuredData::Dictionary *reg_info_dict = nullptr;
+ if (!regs->GetItemAtIndexAsDictionary(i, reg_info_dict))
{
- PythonDictionary reg_info_dict(regs.GetItemAtIndex(i));
- if (reg_info_dict)
- {
- // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
- RegisterInfo reg_info;
- std::vector<uint32_t> value_regs;
- std::vector<uint32_t> invalidate_regs;
- memset(&reg_info, 0, sizeof(reg_info));
-
- reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString();
- if (reg_info.name == NULL)
- {
- Clear();
- printf("error: registers must have valid names\n");
- reg_info_dict.Dump();
- return 0;
- }
-
- reg_info.alt_name = ConstString (reg_info_dict.GetItemForKeyAsString(altname_pystr)).GetCString();
-
- reg_info.byte_offset = reg_info_dict.GetItemForKeyAsInteger(offset_pystr, UINT32_MAX);
+ Clear();
+ printf("error: items in the 'registers' array must be dictionaries\n");
+ regs->DumpToStdout();
+ return 0;
+ }
- if (reg_info.byte_offset == UINT32_MAX)
+ // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2,
+ // 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
+ RegisterInfo reg_info;
+ std::vector<uint32_t> value_regs;
+ std::vector<uint32_t> invalidate_regs;
+ memset(&reg_info, 0, sizeof(reg_info));
+
+ ConstString name_val;
+ ConstString alt_name_val;
+ if (!reg_info_dict->GetValueForKeyAsString("name", name_val, nullptr))
+ {
+ Clear();
+ printf("error: registers must have valid names and offsets\n");
+ reg_info_dict->DumpToStdout();
+ return 0;
+ }
+ reg_info.name = name_val.GetCString();
+ reg_info_dict->GetValueForKeyAsString("alt-name", alt_name_val, nullptr);
+ reg_info.alt_name = alt_name_val.GetCString();
+
+ reg_info_dict->GetValueForKeyAsInteger("offset", reg_info.byte_offset, UINT32_MAX);
+
+ const ByteOrder byte_order = arch.GetByteOrder();
+
+ if (reg_info.byte_offset == UINT32_MAX)
+ {
+ // No offset for this register, see if the register has a value expression
+ // which indicates this register is part of another register. Value expressions
+ // are things like "rax[31:0]" which state that the current register's value
+ // is in a concrete register "rax" in bits 31:0. If there is a value expression
+ // we can calculate the offset
+ bool success = false;
+ std::string slice_str;
+ if (reg_info_dict->GetValueForKeyAsString("slice", slice_str, nullptr))
+ {
+ // Slices use the following format:
+ // REGNAME[MSBIT:LSBIT]
+ // REGNAME - name of the register to grab a slice of
+ // MSBIT - the most significant bit at which the current register value starts at
+ // LSBIT - the least significant bit at which the current register value ends at
+ static RegularExpression g_bitfield_regex("([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]");
+ RegularExpression::Match regex_match(3);
+ if (g_bitfield_regex.Execute(slice_str.c_str(), &regex_match))
{
- // No offset for this register, see if the register has a value expression
- // which indicates this register is part of another register. Value expressions
- // are things like "rax[31:0]" which state that the current register's value
- // is in a concrete register "rax" in bits 31:0. If there is a value expression
- // we can calculate the offset
- bool success = false;
- const char *slice_cstr = reg_info_dict.GetItemForKeyAsString(slice_pystr);
- if (slice_cstr)
+ llvm::StringRef reg_name_str;
+ std::string msbit_str;
+ std::string lsbit_str;
+ if (regex_match.GetMatchAtIndex(slice_str.c_str(), 1, reg_name_str) &&
+ regex_match.GetMatchAtIndex(slice_str.c_str(), 2, msbit_str) &&
+ regex_match.GetMatchAtIndex(slice_str.c_str(), 3, lsbit_str))
{
- // Slices use the following format:
- // REGNAME[MSBIT:LSBIT]
- // REGNAME - name of the register to grab a slice of
- // MSBIT - the most significant bit at which the current register value starts at
- // LSBIT - the least significant bit at which the current register value ends at
- static RegularExpression g_bitfield_regex("([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]");
- RegularExpression::Match regex_match(3);
- if (g_bitfield_regex.Execute(slice_cstr, &regex_match))
+ const uint32_t msbit = StringConvert::ToUInt32(msbit_str.c_str(), UINT32_MAX);
+ const uint32_t lsbit = StringConvert::ToUInt32(lsbit_str.c_str(), UINT32_MAX);
+ if (msbit != UINT32_MAX && lsbit != UINT32_MAX)
{
- llvm::StringRef reg_name_str;
- std::string msbit_str;
- std::string lsbit_str;
- if (regex_match.GetMatchAtIndex(slice_cstr, 1, reg_name_str) &&
- regex_match.GetMatchAtIndex(slice_cstr, 2, msbit_str) &&
- regex_match.GetMatchAtIndex(slice_cstr, 3, lsbit_str))
+ if (msbit > lsbit)
{
- const uint32_t msbit = StringConvert::ToUInt32(msbit_str.c_str(), UINT32_MAX);
- const uint32_t lsbit = StringConvert::ToUInt32(lsbit_str.c_str(), UINT32_MAX);
- if (msbit != UINT32_MAX && lsbit != UINT32_MAX)
+ const uint32_t msbyte = msbit / 8;
+ const uint32_t lsbyte = lsbit / 8;
+
+ ConstString containing_reg_name(reg_name_str);
+
+ RegisterInfo *containing_reg_info = GetRegisterInfo(containing_reg_name);
+ if (containing_reg_info)
{
- if (msbit > lsbit)
+ const uint32_t max_bit = containing_reg_info->byte_size * 8;
+ if (msbit < max_bit && lsbit < max_bit)
{
- const uint32_t msbyte = msbit / 8;
- const uint32_t lsbyte = lsbit / 8;
+ m_invalidate_regs_map[containing_reg_info->kinds[eRegisterKindLLDB]].push_back(i);
+ m_value_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]);
+ m_invalidate_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]);
- ConstString containing_reg_name(reg_name_str);
-
- RegisterInfo *containing_reg_info = GetRegisterInfo (containing_reg_name);
- if (containing_reg_info)
+ if (byte_order == eByteOrderLittle)
+ {
+ success = true;
+ reg_info.byte_offset = containing_reg_info->byte_offset + lsbyte;
+ }
+ else if (byte_order == eByteOrderBig)
{
- const uint32_t max_bit = containing_reg_info->byte_size * 8;
- if (msbit < max_bit && lsbit < max_bit)
- {
- m_invalidate_regs_map[containing_reg_info->kinds[eRegisterKindLLDB]].push_back(i);
- m_value_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]);
- m_invalidate_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]);
-
- if (byte_order == eByteOrderLittle)
- {
- success = true;
- reg_info.byte_offset = containing_reg_info->byte_offset + lsbyte;
- }
- else if (byte_order == eByteOrderBig)
- {
- success = true;
- reg_info.byte_offset = containing_reg_info->byte_offset + msbyte;
- }
- else
- {
- assert(!"Invalid byte order");
- }
- }
- else
- {
- if (msbit > max_bit)
- printf("error: msbit (%u) must be less than the bitsize of the register (%u)\n", msbit, max_bit);
- else
- printf("error: lsbit (%u) must be less than the bitsize of the register (%u)\n", lsbit, max_bit);
- }
+ success = true;
+ reg_info.byte_offset = containing_reg_info->byte_offset + msbyte;
}
else
{
- printf("error: invalid concrete register \"%s\"\n", containing_reg_name.GetCString());
+ assert(!"Invalid byte order");
}
}
else
{
- printf("error: msbit (%u) must be greater than lsbit (%u)\n", msbit, lsbit);
+ if (msbit > max_bit)
+ printf("error: msbit (%u) must be less than the bitsize of the register (%u)\n", msbit,
+ max_bit);
+ else
+ printf("error: lsbit (%u) must be less than the bitsize of the register (%u)\n", lsbit,
+ max_bit);
}
}
else
{
- printf("error: msbit (%u) and lsbit (%u) must be valid\n", msbit, lsbit);
+ printf("error: invalid concrete register \"%s\"\n", containing_reg_name.GetCString());
}
}
else
{
- // TODO: print error invalid slice string that doesn't follow the format
- printf("error: failed to extract regex matches for parsing the register bitfield regex\n");
-
+ printf("error: msbit (%u) must be greater than lsbit (%u)\n", msbit, lsbit);
}
}
else
{
- // TODO: print error invalid slice string that doesn't follow the format
- printf("error: failed to match against register bitfield regex\n");
+ printf("error: msbit (%u) and lsbit (%u) must be valid\n", msbit, lsbit);
}
}
else
{
- PythonList composite_reg_list (reg_info_dict.GetItemForKey(composite_pystr));
- if (composite_reg_list)
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to extract regex matches for parsing the register bitfield regex\n");
+ }
+ }
+ else
+ {
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to match against register bitfield regex\n");
+ }
+ }
+ else
+ {
+ StructuredData::Array *composite_reg_list = nullptr;
+ if (reg_info_dict->GetValueForKeyAsArray("composite", composite_reg_list))
+ {
+ const size_t num_composite_regs = composite_reg_list->GetSize();
+ if (num_composite_regs > 0)
+ {
+ uint32_t composite_offset = UINT32_MAX;
+ for (uint32_t composite_idx = 0; composite_idx < num_composite_regs; ++composite_idx)
{
- const size_t num_composite_regs = composite_reg_list.GetSize();
- if (num_composite_regs > 0)
+ ConstString composite_reg_name;
+ if (composite_reg_list->GetItemAtIndexAsString(composite_idx, composite_reg_name, nullptr))
{
- uint32_t composite_offset = UINT32_MAX;
- for (uint32_t composite_idx=0; composite_idx<num_composite_regs; ++composite_idx)
+ RegisterInfo *composite_reg_info = GetRegisterInfo(composite_reg_name);
+ if (composite_reg_info)
{
- PythonString composite_reg_name_pystr(composite_reg_list.GetItemAtIndex(composite_idx));
- if (composite_reg_name_pystr)
- {
- ConstString composite_reg_name(composite_reg_name_pystr.GetString());
- if (composite_reg_name)
- {
- RegisterInfo *composite_reg_info = GetRegisterInfo (composite_reg_name);
- if (composite_reg_info)
- {
- if (composite_offset > composite_reg_info->byte_offset)
- composite_offset = composite_reg_info->byte_offset;
- m_value_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]);
- m_invalidate_regs_map[composite_reg_info->kinds[eRegisterKindLLDB]].push_back(i);
- m_invalidate_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]);
- }
- else
- {
- // TODO: print error invalid slice string that doesn't follow the format
- printf("error: failed to find composite register by name: \"%s\"\n", composite_reg_name.GetCString());
- }
- }
- else
- {
- printf("error: 'composite' key contained an empty string\n");
- }
- }
- else
- {
- printf("error: 'composite' list value wasn't a python string\n");
- }
- }
- if (composite_offset != UINT32_MAX)
- {
- reg_info.byte_offset = composite_offset;
- success = m_value_regs_map.find(i) != m_value_regs_map.end();
+ composite_offset = std::min(composite_offset, composite_reg_info->byte_offset);
+ m_value_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]);
+ m_invalidate_regs_map[composite_reg_info->kinds[eRegisterKindLLDB]].push_back(i);
+ m_invalidate_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]);
}
else
{
- printf("error: 'composite' registers must specify at least one real register\n");
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to find composite register by name: \"%s\"\n", composite_reg_name.GetCString());
}
}
else
{
- printf("error: 'composite' list was empty\n");
+ printf("error: 'composite' list value wasn't a python string\n");
}
}
+ if (composite_offset != UINT32_MAX)
+ {
+ reg_info.byte_offset = composite_offset;
+ success = m_value_regs_map.find(i) != m_value_regs_map.end();
+ }
+ else
+ {
+ printf("error: 'composite' registers must specify at least one real register\n");
+ }
}
-
-
- if (!success)
+ else
{
- Clear();
- reg_info_dict.Dump();
- return 0;
+ printf("error: 'composite' list was empty\n");
}
}
- const int64_t bitsize = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0);
- if (bitsize == 0)
- {
- Clear();
- printf("error: invalid or missing 'bitsize' key/value pair in register dictionary\n");
- reg_info_dict.Dump();
- return 0;
- }
+ }
- reg_info.byte_size = bitsize / 8;
-
- const char *format_cstr = reg_info_dict.GetItemForKeyAsString(format_pystr);
- if (format_cstr)
- {
- if (Args::StringToFormat(format_cstr, reg_info.format, NULL).Fail())
- {
- Clear();
- printf("error: invalid 'format' value in register dictionary\n");
- reg_info_dict.Dump();
- return 0;
- }
- }
- else
- {
- reg_info.format = (Format)reg_info_dict.GetItemForKeyAsInteger (format_pystr, eFormatHex);
- }
-
- const char *encoding_cstr = reg_info_dict.GetItemForKeyAsString(encoding_pystr);
- if (encoding_cstr)
- reg_info.encoding = Args::StringToEncoding (encoding_cstr, eEncodingUint);
- else
- reg_info.encoding = (Encoding)reg_info_dict.GetItemForKeyAsInteger (encoding_pystr, eEncodingUint);
+ if (!success)
+ {
+ Clear();
+ reg_info_dict->DumpToStdout();
+ return 0;
+ }
+ }
- const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1);
- if (static_cast<size_t>(set) >= m_sets.size())
- {
- Clear();
- printf("error: invalid 'set' value in register dictionary, valid values are 0 - %i\n", (int)set);
- reg_info_dict.Dump();
- return 0;
- }
+ int64_t bitsize = 0;
+ if (!reg_info_dict->GetValueForKeyAsInteger("bitsize", bitsize))
+ {
+ Clear();
+ printf("error: invalid or missing 'bitsize' key/value pair in register dictionary\n");
+ reg_info_dict->DumpToStdout();
+ return 0;
+ }
- // Fill in the register numbers
- reg_info.kinds[lldb::eRegisterKindLLDB] = i;
- reg_info.kinds[lldb::eRegisterKindGDB] = i;
- reg_info.kinds[lldb::eRegisterKindGCC] = reg_info_dict.GetItemForKeyAsInteger(gcc_pystr, LLDB_INVALID_REGNUM);
- reg_info.kinds[lldb::eRegisterKindDWARF] = reg_info_dict.GetItemForKeyAsInteger(dwarf_pystr, LLDB_INVALID_REGNUM);
- const char *generic_cstr = reg_info_dict.GetItemForKeyAsString(generic_pystr);
- if (generic_cstr)
- reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (generic_cstr);
- else
- reg_info.kinds[lldb::eRegisterKindGeneric] = reg_info_dict.GetItemForKeyAsInteger(generic_pystr, LLDB_INVALID_REGNUM);
+ reg_info.byte_size = bitsize / 8;
- // Check if this register invalidates any other register values when it is modified
- PythonList invalidate_reg_list (reg_info_dict.GetItemForKey(invalidate_regs_pystr));
- if (invalidate_reg_list)
+ std::string format_str;
+ if (reg_info_dict->GetValueForKeyAsString("format", format_str, nullptr))
+ {
+ if (Args::StringToFormat(format_str.c_str(), reg_info.format, NULL).Fail())
+ {
+ Clear();
+ printf("error: invalid 'format' value in register dictionary\n");
+ reg_info_dict->DumpToStdout();
+ return 0;
+ }
+ }
+ else
+ {
+ reg_info_dict->GetValueForKeyAsInteger("format", reg_info.format, eFormatHex);
+ }
+
+ std::string encoding_str;
+ if (reg_info_dict->GetValueForKeyAsString("encoding", encoding_str))
+ reg_info.encoding = Args::StringToEncoding(encoding_str.c_str(), eEncodingUint);
+ else
+ reg_info_dict->GetValueForKeyAsInteger("encoding", reg_info.encoding, eEncodingUint);
+
+ size_t set = 0;
+ if (!reg_info_dict->GetValueForKeyAsInteger<size_t>("set", set, -1) || set >= m_sets.size())
+ {
+ Clear();
+ printf("error: invalid 'set' value in register dictionary, valid values are 0 - %i\n", (int)set);
+ reg_info_dict->DumpToStdout();
+ return 0;
+ }
+
+ // Fill in the register numbers
+ reg_info.kinds[lldb::eRegisterKindLLDB] = i;
+ reg_info.kinds[lldb::eRegisterKindGDB] = i;
+ reg_info_dict->GetValueForKeyAsInteger("gcc", reg_info.kinds[lldb::eRegisterKindGCC], LLDB_INVALID_REGNUM);
+ reg_info_dict->GetValueForKeyAsInteger("dwarf", reg_info.kinds[lldb::eRegisterKindDWARF], LLDB_INVALID_REGNUM);
+ std::string generic_str;
+ if (reg_info_dict->GetValueForKeyAsString("generic", generic_str))
+ reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister(generic_str.c_str());
+ else
+ reg_info_dict->GetValueForKeyAsInteger("generic", reg_info.kinds[lldb::eRegisterKindGeneric], LLDB_INVALID_REGNUM);
+
+ // Check if this register invalidates any other register values when it is modified
+ StructuredData::Array *invalidate_reg_list = nullptr;
+ if (reg_info_dict->GetValueForKeyAsArray("invalidate-regs", invalidate_reg_list))
+ {
+ const size_t num_regs = invalidate_reg_list->GetSize();
+ if (num_regs > 0)
+ {
+ for (uint32_t idx = 0; idx < num_regs; ++idx)
{
- const size_t num_regs = invalidate_reg_list.GetSize();
- if (num_regs > 0)
+ ConstString invalidate_reg_name;
+ uint64_t invalidate_reg_num;
+ if (invalidate_reg_list->GetItemAtIndexAsString(idx, invalidate_reg_name))
{
- for (uint32_t idx=0; idx<num_regs; ++idx)
+ RegisterInfo *invalidate_reg_info = GetRegisterInfo(invalidate_reg_name);
+ if (invalidate_reg_info)
{
- PythonObject invalidate_reg_object (invalidate_reg_list.GetItemAtIndex(idx));
- PythonString invalidate_reg_name_pystr(invalidate_reg_object);
- if (invalidate_reg_name_pystr)
- {
- ConstString invalidate_reg_name(invalidate_reg_name_pystr.GetString());
- if (invalidate_reg_name)
- {
- RegisterInfo *invalidate_reg_info = GetRegisterInfo (invalidate_reg_name);
- if (invalidate_reg_info)
- {
- m_invalidate_regs_map[i].push_back(invalidate_reg_info->kinds[eRegisterKindLLDB]);
- }
- else
- {
- // TODO: print error invalid slice string that doesn't follow the format
- printf("error: failed to find a 'invalidate-regs' register for \"%s\" while parsing register \"%s\"\n", invalidate_reg_name.GetCString(), reg_info.name);
- }
- }
- else
- {
- printf("error: 'invalidate-regs' list value was an empty string\n");
- }
- }
- else
- {
- PythonInteger invalidate_reg_num(invalidate_reg_object);
-
- if (invalidate_reg_num)
- {
- const int64_t r = invalidate_reg_num.GetInteger();
- 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");
- }
- else
- {
- printf("error: 'invalidate-regs' list value wasn't a python string or integer\n");
- }
- }
+ m_invalidate_regs_map[i].push_back(invalidate_reg_info->kinds[eRegisterKindLLDB]);
+ }
+ else
+ {
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to find a 'invalidate-regs' register for \"%s\" while parsing register \"%s\"\n",
+ invalidate_reg_name.GetCString(), reg_info.name);
}
}
+ else if (invalidate_reg_list->GetItemAtIndexAsInteger(idx, invalidate_reg_num))
+ {
+ if (invalidate_reg_num != UINT64_MAX)
+ m_invalidate_regs_map[i].push_back(invalidate_reg_num);
+ else
+ printf("error: 'invalidate-regs' list value wasn't a valid integer\n");
+ }
else
{
- printf("error: 'invalidate-regs' contained an empty list\n");
+ printf("error: 'invalidate-regs' list value wasn't a python string or integer\n");
}
}
-
- // Calculate the register offset
- const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
- if (m_reg_data_byte_size < end_reg_offset)
- m_reg_data_byte_size = end_reg_offset;
-
- m_regs.push_back (reg_info);
- m_set_reg_nums[set].push_back(i);
-
}
else
{
- Clear();
- printf("error: items in the 'registers' array must be dictionaries\n");
- regs.Dump();
- return 0;
+ printf("error: 'invalidate-regs' contained an empty list\n");
}
}
- Finalize ();
+
+ // Calculate the register offset
+ const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
+ if (m_reg_data_byte_size < end_reg_offset)
+ m_reg_data_byte_size = end_reg_offset;
+
+ m_regs.push_back(reg_info);
+ m_set_reg_nums[set].push_back(i);
}
-#endif
+ Finalize(arch);
return m_regs.size();
}
@@ -465,7 +425,7 @@ DynamicRegisterInfo::AddRegister (RegisterInfo &reg_info,
}
void
-DynamicRegisterInfo::Finalize ()
+DynamicRegisterInfo::Finalize (const ArchSpec &arch)
{
if (m_finalized)
return;
@@ -560,6 +520,95 @@ DynamicRegisterInfo::Finalize ()
else
m_regs[i].invalidate_regs = NULL;
}
+
+ // Check if we need to automatically set the generic registers in case
+ // they weren't set
+ bool generic_regs_specified = false;
+ for (const auto &reg: m_regs)
+ {
+ if (reg.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM)
+ {
+ generic_regs_specified = true;
+ break;
+ }
+ }
+
+ if (!generic_regs_specified)
+ {
+ switch (arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ for (auto &reg: m_regs)
+ {
+ if (strcmp(reg.name, "pc") == 0)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ else if ((strcmp(reg.name, "fp") == 0) || (strcmp(reg.name, "x29") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if ((strcmp(reg.name, "lr") == 0) || (strcmp(reg.name, "x30") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
+ else if ((strcmp(reg.name, "sp") == 0) || (strcmp(reg.name, "x31") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+ else if (strcmp(reg.name, "cpsr") == 0)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ for (auto &reg: m_regs)
+ {
+ if ((strcmp(reg.name, "pc") == 0) || (strcmp(reg.name, "r15") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ else if ((strcmp(reg.name, "sp") == 0) || (strcmp(reg.name, "r13") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+ else if ((strcmp(reg.name, "lr") == 0) || (strcmp(reg.name, "r14") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
+ else if ((strcmp(reg.name, "r7") == 0) && arch.GetTriple().getVendor() == llvm::Triple::Apple)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if ((strcmp(reg.name, "r11") == 0) && arch.GetTriple().getVendor() != llvm::Triple::Apple)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if (strcmp(reg.name, "fp") == 0)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if (strcmp(reg.name, "cpsr") == 0)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ }
+ break;
+
+ case llvm::Triple::x86:
+ for (auto &reg: m_regs)
+ {
+ if ((strcmp(reg.name, "eip") == 0) || (strcmp(reg.name, "pc") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ else if ((strcmp(reg.name, "esp") == 0) || (strcmp(reg.name, "sp") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+ else if ((strcmp(reg.name, "ebp") == 0) || (strcmp(reg.name, "fp") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if ((strcmp(reg.name, "eflags") == 0) || (strcmp(reg.name, "flags") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ }
+ break;
+
+ case llvm::Triple::x86_64:
+ for (auto &reg: m_regs)
+ {
+ if ((strcmp(reg.name, "rip") == 0) || (strcmp(reg.name, "pc") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ else if ((strcmp(reg.name, "rsp") == 0) || (strcmp(reg.name, "sp") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+ else if ((strcmp(reg.name, "rbp") == 0) || (strcmp(reg.name, "fp") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if ((strcmp(reg.name, "rflags") == 0) || (strcmp(reg.name, "flags") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
}
size_t
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/source/Plugins/Process/Utility/DynamicRegisterInfo.h
index a41c77e49f9d..1b99e2f1e701 100644
--- a/source/Plugins/Process/Utility/DynamicRegisterInfo.h
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.h
@@ -19,21 +19,21 @@
// Project includes
#include "lldb/lldb-private.h"
#include "lldb/Core/ConstString.h"
+#include "lldb/Core/StructuredData.h"
class DynamicRegisterInfo
{
public:
DynamicRegisterInfo ();
- DynamicRegisterInfo (const lldb_private::PythonDictionary &dict,
- lldb::ByteOrder byte_order);
-
+ DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict,
+ const lldb_private::ArchSpec &arch);
+
virtual
~DynamicRegisterInfo ();
- size_t
- SetRegisterInfo (const lldb_private::PythonDictionary &dict,
- lldb::ByteOrder byte_order);
+ size_t SetRegisterInfo(const lldb_private::StructuredData::Dictionary &dict,
+ const lldb_private::ArchSpec &arch);
void
AddRegister (lldb_private::RegisterInfo &reg_info,
@@ -42,7 +42,7 @@ public:
lldb_private::ConstString &set_name);
void
- Finalize ();
+ Finalize (const lldb_private::ArchSpec &arch);
size_t
GetNumRegisters() const;
diff --git a/source/Plugins/Process/Utility/FreeBSDSignals.cpp b/source/Plugins/Process/Utility/FreeBSDSignals.cpp
index b7c52aeb6d13..f082e143059c 100644
--- a/source/Plugins/Process/Utility/FreeBSDSignals.cpp
+++ b/source/Plugins/Process/Utility/FreeBSDSignals.cpp
@@ -24,8 +24,70 @@ 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");
+ // 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");
+ AddSignal (65, "SIGRTMIN", "RTMIN", false, true , true , "real time signal 0");
+ AddSignal (66, "SIGRTMIN+1", "RTMIN+1", false, true , true , "real time signal 1");
+ AddSignal (67, "SIGRTMIN+2", "RTMIN+2", false, true , true , "real time signal 2");
+ AddSignal (68, "SIGRTMIN+3", "RTMIN+3", false, true , true , "real time signal 3");
+ AddSignal (69, "SIGRTMIN+4", "RTMIN+4", false, true , true , "real time signal 4");
+ AddSignal (70, "SIGRTMIN+5", "RTMIN+5", false, true , true , "real time signal 5");
+ AddSignal (71, "SIGRTMIN+6", "RTMIN+6", false, true , true , "real time signal 6");
+ AddSignal (72, "SIGRTMIN+7", "RTMIN+7", false, true , true , "real time signal 7");
+ AddSignal (73, "SIGRTMIN+8", "RTMIN+8", false, true , true , "real time signal 8");
+ AddSignal (74, "SIGRTMIN+9", "RTMIN+9", false, true , true , "real time signal 9");
+ AddSignal (75, "SIGRTMIN+10", "RTMIN+10", false, true , true , "real time signal 10");
+ AddSignal (76, "SIGRTMIN+11", "RTMIN+11", false, true , true , "real time signal 11");
+ AddSignal (77, "SIGRTMIN+12", "RTMIN+12", false, true , true , "real time signal 12");
+ AddSignal (78, "SIGRTMIN+13", "RTMIN+13", false, true , true , "real time signal 13");
+ AddSignal (79, "SIGRTMIN+14", "RTMIN+14", false, true , true , "real time signal 14");
+ AddSignal (80, "SIGRTMIN+15", "RTMIN+15", false, true , true , "real time signal 15");
+ AddSignal (81, "SIGRTMIN+16", "RTMIN+16", false, true , true , "real time signal 16");
+ AddSignal (82, "SIGRTMIN+17", "RTMIN+17", false, true , true , "real time signal 17");
+ AddSignal (83, "SIGRTMIN+18", "RTMIN+18", false, true , true , "real time signal 18");
+ AddSignal (84, "SIGRTMIN+19", "RTMIN+19", false, true , true , "real time signal 19");
+ AddSignal (85, "SIGRTMIN+20", "RTMIN+20", false, true , true , "real time signal 20");
+ AddSignal (86, "SIGRTMIN+21", "RTMIN+21", false, true , true , "real time signal 21");
+ AddSignal (87, "SIGRTMIN+22", "RTMIN+22", false, true , true , "real time signal 22");
+ AddSignal (88, "SIGRTMIN+23", "RTMIN+23", false, true , true , "real time signal 23");
+ AddSignal (89, "SIGRTMIN+24", "RTMIN+24", false, true , true , "real time signal 24");
+ AddSignal (90, "SIGRTMIN+25", "RTMIN+25", false, true , true , "real time signal 25");
+ AddSignal (91, "SIGRTMIN+26", "RTMIN+26", false, true , true , "real time signal 26");
+ AddSignal (92, "SIGRTMIN+27", "RTMIN+27", false, true , true , "real time signal 27");
+ AddSignal (93, "SIGRTMIN+28", "RTMIN+28", false, true , true , "real time signal 28");
+ AddSignal (94, "SIGRTMIN+29", "RTMIN+29", false, true , true , "real time signal 29");
+ AddSignal (95, "SIGRTMIN+30", "RTMIN+30", false, true , true , "real time signal 30");
+ AddSignal (96, "SIGRTMAX-30", "RTMAX-30", false, true , true , "real time signal 31");
+ AddSignal (97, "SIGRTMAX-29", "RTMAX-29", false, true , true , "real time signal 32");
+ AddSignal (98, "SIGRTMAX-28", "RTMAX-28", false, true , true , "real time signal 33");
+ AddSignal (99, "SIGRTMAX-27", "RTMAX-27", false, true , true , "real time signal 34");
+ AddSignal (100, "SIGRTMAX-26", "RTMAX-26", false, true , true , "real time signal 35");
+ AddSignal (101, "SIGRTMAX-25", "RTMAX-25", false, true , true , "real time signal 36");
+ AddSignal (102, "SIGRTMAX-24", "RTMAX-24", false, true , true , "real time signal 37");
+ AddSignal (103, "SIGRTMAX-23", "RTMAX-23", false, true , true , "real time signal 38");
+ AddSignal (104, "SIGRTMAX-22", "RTMAX-22", false, true , true , "real time signal 39");
+ AddSignal (105, "SIGRTMAX-21", "RTMAX-21", false, true , true , "real time signal 40");
+ AddSignal (106, "SIGRTMAX-20", "RTMAX-20", false, true , true , "real time signal 41");
+ AddSignal (107, "SIGRTMAX-19", "RTMAX-19", false, true , true , "real time signal 42");
+ AddSignal (108, "SIGRTMAX-18", "RTMAX-18", false, true , true , "real time signal 43");
+ AddSignal (109, "SIGRTMAX-17", "RTMAX-17", false, true , true , "real time signal 44");
+ AddSignal (110, "SIGRTMAX-16", "RTMAX-16", false, true , true , "real time signal 45");
+ AddSignal (111, "SIGRTMAX-15", "RTMAX-15", false, true , true , "real time signal 46");
+ AddSignal (112, "SIGRTMAX-14", "RTMAX-14", false, true , true , "real time signal 47");
+ AddSignal (113, "SIGRTMAX-13", "RTMAX-13", false, true , true , "real time signal 48");
+ AddSignal (114, "SIGRTMAX-12", "RTMAX-12", false, true , true , "real time signal 49");
+ AddSignal (115, "SIGRTMAX-11", "RTMAX-11", false, true , true , "real time signal 50");
+ AddSignal (116, "SIGRTMAX-10", "RTMAX-10", false, true , true , "real time signal 51");
+ AddSignal (117, "SIGRTMAX-9", "RTMAX-9", false, true , true , "real time signal 52");
+ AddSignal (118, "SIGRTMAX-8", "RTMAX-8", false, true , true , "real time signal 53");
+ AddSignal (119, "SIGRTMAX-7", "RTMAX-7", false, true , true , "real time signal 54");
+ AddSignal (120, "SIGRTMAX-6", "RTMAX-6", false, true , true , "real time signal 55");
+ AddSignal (121, "SIGRTMAX-5", "RTMAX-5", false, true , true , "real time signal 56");
+ AddSignal (122, "SIGRTMAX-4", "RTMAX-4", false, true , true , "real time signal 57");
+ AddSignal (123, "SIGRTMAX-3", "RTMAX-3", false, true , true , "real time signal 58");
+ AddSignal (124, "SIGRTMAX-2", "RTMAX-2", false, true , true , "real time signal 59");
+ AddSignal (125, "SIGRTMAX-1", "RTMAX-1", false, true , true , "real time signal 60");
+ AddSignal (126, "SIGRTMAX", "RTMAX", false, true , true , "real time signal 61");
}
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index 7db83ae5467f..3923c5433406 100644
--- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -14,6 +14,7 @@
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
@@ -27,8 +28,6 @@
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_EXEC 4
-#define MAP_PRIVATE 2
-#define MAP_ANON 0x1000
#endif
using namespace lldb;
@@ -87,10 +86,8 @@ lldb_private::InferiorCallMmap (Process *process,
prot_arg |= PROT_WRITE;
}
- if (flags & eMmapFlagsPrivate)
- flags_arg |= MAP_PRIVATE;
- if (flags & eMmapFlagsAnon)
- flags_arg |= MAP_ANON;
+ const ArchSpec arch = process->GetTarget().GetArchitecture();
+ flags_arg = process->GetTarget().GetPlatform()->ConvertMmapFlagsToPlatform(arch,flags);
AddressRange mmap_range;
if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, mmap_range))
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.h b/source/Plugins/Process/Utility/InferiorCallPOSIX.h
index d8b6d0ed57fd..e56e95c43773 100644
--- a/source/Plugins/Process/Utility/InferiorCallPOSIX.h
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.h
@@ -25,11 +25,6 @@ enum MmapProt {
eMmapProtWrite = 4
};
-enum MmapFlags {
- eMmapFlagsPrivate = 1,
- eMmapFlagsAnon = 2
-};
-
bool InferiorCallMmap(Process *proc, lldb::addr_t &allocated_addr,
lldb::addr_t addr, lldb::addr_t length, unsigned prot,
unsigned flags, lldb::addr_t fd, lldb::addr_t offset);
diff --git a/source/Plugins/Process/Utility/LinuxSignals.cpp b/source/Plugins/Process/Utility/LinuxSignals.cpp
index 11a3eef23529..0680d268233c 100644
--- a/source/Plugins/Process/Utility/LinuxSignals.cpp
+++ b/source/Plugins/Process/Utility/LinuxSignals.cpp
@@ -12,7 +12,7 @@
// Project includes
#include "LinuxSignals.h"
-using namespace process_linux;
+using namespace lldb_private::process_linux;
LinuxSignals::LinuxSignals()
: UnixSignals()
@@ -25,38 +25,71 @@ 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, false, false, "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");
+ 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, false, false, "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");
+ AddSignal (32, "SIG32", "SIG32", false, true , true , "threading library internal signal 1");
+ AddSignal (33, "SIG33", "SIG33", false, true , true , "threading library internal signal 2");
+ AddSignal (34, "SIGRTMIN", "RTMIN", false, true , true , "real time signal 0");
+ AddSignal (35, "SIGRTMIN+1", "RTMIN+1", false, true , true , "real time signal 1");
+ AddSignal (36, "SIGRTMIN+2", "RTMIN+2", false, true , true , "real time signal 2");
+ AddSignal (37, "SIGRTMIN+3", "RTMIN+3", false, true , true , "real time signal 3");
+ AddSignal (38, "SIGRTMIN+4", "RTMIN+4", false, true , true , "real time signal 4");
+ AddSignal (39, "SIGRTMIN+5", "RTMIN+5", false, true , true , "real time signal 5");
+ AddSignal (40, "SIGRTMIN+6", "RTMIN+6", false, true , true , "real time signal 6");
+ AddSignal (41, "SIGRTMIN+7", "RTMIN+7", false, true , true , "real time signal 7");
+ AddSignal (42, "SIGRTMIN+8", "RTMIN+8", false, true , true , "real time signal 8");
+ AddSignal (43, "SIGRTMIN+9", "RTMIN+9", false, true , true , "real time signal 9");
+ AddSignal (44, "SIGRTMIN+10", "RTMIN+10", false, true , true , "real time signal 10");
+ AddSignal (45, "SIGRTMIN+11", "RTMIN+11", false, true , true , "real time signal 11");
+ AddSignal (46, "SIGRTMIN+12", "RTMIN+12", false, true , true , "real time signal 12");
+ AddSignal (47, "SIGRTMIN+13", "RTMIN+13", false, true , true , "real time signal 13");
+ AddSignal (48, "SIGRTMIN+14", "RTMIN+14", false, true , true , "real time signal 14");
+ AddSignal (49, "SIGRTMIN+15", "RTMIN+15", false, true , true , "real time signal 15");
+ AddSignal (50, "SIGRTMAX-14", "RTMAX-14", false, true , true , "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output
+ AddSignal (51, "SIGRTMAX-13", "RTMAX-13", false, true , true , "real time signal 17");
+ AddSignal (52, "SIGRTMAX-12", "RTMAX-12", false, true , true , "real time signal 18");
+ AddSignal (53, "SIGRTMAX-11", "RTMAX-11", false, true , true , "real time signal 19");
+ AddSignal (54, "SIGRTMAX-10", "RTMAX-10", false, true , true , "real time signal 20");
+ AddSignal (55, "SIGRTMAX-9", "RTMAX-9", false, true , true , "real time signal 21");
+ AddSignal (56, "SIGRTMAX-8", "RTMAX-8", false, true , true , "real time signal 22");
+ AddSignal (57, "SIGRTMAX-7", "RTMAX-7", false, true , true , "real time signal 23");
+ AddSignal (58, "SIGRTMAX-6", "RTMAX-6", false, true , true , "real time signal 24");
+ AddSignal (59, "SIGRTMAX-5", "RTMAX-5", false, true , true , "real time signal 25");
+ AddSignal (60, "SIGRTMAX-4", "RTMAX-4", false, true , true , "real time signal 26");
+ AddSignal (61, "SIGRTMAX-3", "RTMAX-3", false, true , true , "real time signal 27");
+ AddSignal (62, "SIGRTMAX-2", "RTMAX-2", false, true , true , "real time signal 28");
+ AddSignal (63, "SIGRTMAX-1", "RTMAX-1", false, true , true , "real time signal 29");
+ AddSignal (64, "SIGRTMAX", "RTMAX", false, true , true , "real time signal 30");
}
diff --git a/source/Plugins/Process/Utility/LinuxSignals.h b/source/Plugins/Process/Utility/LinuxSignals.h
index 9645b3d8725a..5102bcb95e74 100644
--- a/source/Plugins/Process/Utility/LinuxSignals.h
+++ b/source/Plugins/Process/Utility/LinuxSignals.h
@@ -16,8 +16,8 @@
// Project includes
#include "lldb/Target/UnixSignals.h"
-namespace process_linux
-{
+namespace lldb_private {
+namespace process_linux {
/// Linux specific set of Unix signals.
class LinuxSignals
@@ -30,6 +30,8 @@ namespace process_linux
void
Reset();
};
-}
+
+} // namespace lldb_private
+} // namespace process_linux
#endif
diff --git a/source/Plugins/Process/Utility/MipsLinuxSignals.cpp b/source/Plugins/Process/Utility/MipsLinuxSignals.cpp
new file mode 100644
index 000000000000..e4e654626eaa
--- /dev/null
+++ b/source/Plugins/Process/Utility/MipsLinuxSignals.cpp
@@ -0,0 +1,95 @@
+//===-- MipsLinuxSignals.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 "MipsLinuxSignals.h"
+
+using namespace lldb_private::process_linux;
+
+MipsLinuxSignals::MipsLinuxSignals()
+ : UnixSignals()
+{
+ Reset();
+}
+
+void
+MipsLinuxSignals::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, "SIGEMT", "EMT", false, true , true , "terminate process with core dump");
+ AddSignal (8, "SIGFPE", "FPE", false, true , true , "floating point exception");
+ AddSignal (9, "SIGKILL", "KILL", false, true , true , "kill");
+ AddSignal (10, "SIGBUS", "BUS", false, true , true , "bus error");
+ AddSignal (11, "SIGSEGV", "SEGV", false, true , true , "segmentation violation");
+ AddSignal (12, "SIGSYS", "SYS", false, true , true , "invalid system call");
+ 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, "SIGUSR1", "USR1", false, true , true , "user defined signal 1");
+ AddSignal (17, "SIGUSR2", "USR2", false, true , true , "user defined signal 2");
+ AddSignal (18, "SIGCLD", "CLD", false, false, true , "same as SIGCHLD");
+ AddSignal (18, "SIGCHLD", "CHLD", false, false, true , "child status has changed");
+ AddSignal (19, "SIGPWR", "PWR", false, true , true , "power failure");
+ AddSignal (20, "SIGWINCH", "WINCH", false, true , true , "window size changes");
+ AddSignal (21, "SIGURG", "URG", false, true , true , "urgent data on socket");
+ AddSignal (22, "SIGIO", "IO", false, true , true , "input/output ready");
+ AddSignal (22, "SIGPOLL", "POLL", false, true , true , "pollable event");
+ AddSignal (23, "SIGSTOP", "STOP", true , true , true , "process stop");
+ AddSignal (24, "SIGTSTP", "TSTP", false, true , true , "tty stop");
+ AddSignal (25, "SIGCONT", "CONT", false, true , true , "process continue");
+ AddSignal (26, "SIGTTIN", "TTIN", false, true , true , "background tty read");
+ AddSignal (27, "SIGTTOU", "TTOU", false, true , true , "background tty write");
+ AddSignal (28, "SIGVTALRM", "VTALRM", false, true , true , "virtual time alarm");
+ AddSignal (29, "SIGPROF", "PROF", false, false, false, "profiling time alarm");
+ AddSignal (30, "SIGXCPU", "XCPU", false, true , true , "CPU resource exceeded");
+ AddSignal (31, "SIGXFSZ", "XFSZ", false, true , true , "file size limit exceeded");
+ AddSignal (32, "SIG32", "SIG32", false, true , true , "threading library internal signal 1");
+ AddSignal (33, "SIG33", "SIG33", false, true , true , "threading library internal signal 2");
+ AddSignal (34, "SIGRTMIN", "RTMIN", false, true , true , "real time signal 0");
+ AddSignal (35, "SIGRTMIN+1", "RTMIN+1", false, true , true , "real time signal 1");
+ AddSignal (36, "SIGRTMIN+2", "RTMIN+2", false, true , true , "real time signal 2");
+ AddSignal (37, "SIGRTMIN+3", "RTMIN+3", false, true , true , "real time signal 3");
+ AddSignal (38, "SIGRTMIN+4", "RTMIN+4", false, true , true , "real time signal 4");
+ AddSignal (39, "SIGRTMIN+5", "RTMIN+5", false, true , true , "real time signal 5");
+ AddSignal (40, "SIGRTMIN+6", "RTMIN+6", false, true , true , "real time signal 6");
+ AddSignal (41, "SIGRTMIN+7", "RTMIN+7", false, true , true , "real time signal 7");
+ AddSignal (42, "SIGRTMIN+8", "RTMIN+8", false, true , true , "real time signal 8");
+ AddSignal (43, "SIGRTMIN+9", "RTMIN+9", false, true , true , "real time signal 9");
+ AddSignal (44, "SIGRTMIN+10", "RTMIN+10", false, true , true , "real time signal 10");
+ AddSignal (45, "SIGRTMIN+11", "RTMIN+11", false, true , true , "real time signal 11");
+ AddSignal (46, "SIGRTMIN+12", "RTMIN+12", false, true , true , "real time signal 12");
+ AddSignal (47, "SIGRTMIN+13", "RTMIN+13", false, true , true , "real time signal 13");
+ AddSignal (48, "SIGRTMIN+14", "RTMIN+14", false, true , true , "real time signal 14");
+ AddSignal (49, "SIGRTMIN+15", "RTMIN+15", false, true , true , "real time signal 15");
+ AddSignal (50, "SIGRTMAX-14", "RTMAX-14", false, true , true , "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output
+ AddSignal (51, "SIGRTMAX-13", "RTMAX-13", false, true , true , "real time signal 17");
+ AddSignal (52, "SIGRTMAX-12", "RTMAX-12", false, true , true , "real time signal 18");
+ AddSignal (53, "SIGRTMAX-11", "RTMAX-11", false, true , true , "real time signal 19");
+ AddSignal (54, "SIGRTMAX-10", "RTMAX-10", false, true , true , "real time signal 20");
+ AddSignal (55, "SIGRTMAX-9", "RTMAX-9", false, true , true , "real time signal 21");
+ AddSignal (56, "SIGRTMAX-8", "RTMAX-8", false, true , true , "real time signal 22");
+ AddSignal (57, "SIGRTMAX-7", "RTMAX-7", false, true , true , "real time signal 23");
+ AddSignal (58, "SIGRTMAX-6", "RTMAX-6", false, true , true , "real time signal 24");
+ AddSignal (59, "SIGRTMAX-5", "RTMAX-5", false, true , true , "real time signal 25");
+ AddSignal (60, "SIGRTMAX-4", "RTMAX-4", false, true , true , "real time signal 26");
+ AddSignal (61, "SIGRTMAX-3", "RTMAX-3", false, true , true , "real time signal 27");
+ AddSignal (62, "SIGRTMAX-2", "RTMAX-2", false, true , true , "real time signal 28");
+ AddSignal (63, "SIGRTMAX-1", "RTMAX-1", false, true , true , "real time signal 29");
+ AddSignal (64, "SIGRTMAX", "RTMAX", false, true , true , "real time signal 30");
+}
diff --git a/source/Plugins/Process/Utility/MipsLinuxSignals.h b/source/Plugins/Process/Utility/MipsLinuxSignals.h
new file mode 100644
index 000000000000..2e603fbbdf3c
--- /dev/null
+++ b/source/Plugins/Process/Utility/MipsLinuxSignals.h
@@ -0,0 +1,37 @@
+//===-- MipsLinuxSignals.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_MipsLinuxSignals_H_
+#define liblldb_MipsLinuxSignals_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/UnixSignals.h"
+
+namespace lldb_private {
+namespace process_linux {
+
+ /// Linux specific set of Unix signals.
+ class MipsLinuxSignals
+ : public lldb_private::UnixSignals
+ {
+ public:
+ MipsLinuxSignals();
+
+ private:
+ void
+ Reset();
+ };
+
+} // namespace lldb_private
+} // namespace process_linux
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp
new file mode 100644
index 000000000000..8005a6339f6d
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp
@@ -0,0 +1,88 @@
+//===-- RegisterContextFreeBSD_arm.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 "RegisterContextFreeBSD_arm.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Based on RegisterContextLinux_arm.cpp and
+// http://svnweb.freebsd.org/base/head/sys/arm/include/reg.h
+#define GPR_OFFSET(idx) ((idx) * 4)
+#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextFreeBSD_arm::GPR))
+#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU))
+#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm::DBG, reg) + sizeof (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU) + sizeof (RegisterContextFreeBSD_arm::EXC)))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextFreeBSD_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(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 (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU) + sizeof (RegisterContextFreeBSD_arm::EXC))
+
+//-----------------------------------------------------------------------------
+// Include RegisterInfos_arm to declare our g_register_infos_arm structure.
+//-----------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_ARM_STRUCT
+#include "RegisterInfos_arm.h"
+#undef DECLARE_REGISTER_INFOS_ARM_STRUCT
+
+static const lldb_private::RegisterInfo *
+GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ return g_register_infos_arm;
+ 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::arm:
+ return static_cast<uint32_t>(sizeof(g_register_infos_arm) / sizeof(g_register_infos_arm[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextFreeBSD_arm::RegisterContextFreeBSD_arm(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
+RegisterContextFreeBSD_arm::GetGPRSize() const
+{
+ return sizeof(struct RegisterContextFreeBSD_arm::GPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextFreeBSD_arm::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextFreeBSD_arm::GetRegisterCount() const
+{
+ return m_register_info_count;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h
new file mode 100644
index 000000000000..c4287e9f0a47
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h
@@ -0,0 +1,75 @@
+//===-- RegisterContextFreeBSD_arm.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_RegisterContextFreeBSD_arm_h_
+#define liblldb_RegisterContextFreeBSD_arm_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterInfoInterface.h"
+
+class RegisterContextFreeBSD_arm
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+
+ struct GPR
+ {
+ uint32_t r[16]; // R0-R15
+ uint32_t cpsr; // CPSR
+ };
+
+
+ struct QReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ union {
+ uint32_t s[32];
+ uint64_t d[32];
+ QReg q[16]; // the 128-bit NEON registers
+ } floats;
+ uint32_t fpscr;
+ };
+ struct EXC
+ {
+ uint32_t exception;
+ uint32_t fsr; /* Fault status */
+ uint32_t far; /* Virtual Fault Address */
+ };
+
+ struct DBG
+ {
+ uint32_t bvr[16];
+ uint32_t bcr[16];
+ uint32_t wvr[16];
+ uint32_t wcr[16];
+ };
+
+ RegisterContextFreeBSD_arm(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 // liblldb_RegisterContextFreeBSD_arm_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp
new file mode 100644
index 000000000000..d39a9da5714b
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp
@@ -0,0 +1,86 @@
+//===-- RegisterContextFreeBSD_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 <vector>
+#include "RegisterContextPOSIX_arm64.h"
+#include "RegisterContextFreeBSD_arm64.h"
+
+using namespace lldb;
+
+// Based on RegisterContextDarwin_arm64.cpp
+#define GPR_OFFSET(idx) ((idx) * 8)
+#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::GPR, reg))
+
+#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextFreeBSD_arm64::GPR))
+#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::FPU, reg))
+
+#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::EXC, reg) + sizeof (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU))
+#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::DBG, reg) + sizeof (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU) + sizeof (RegisterContextFreeBSD_arm64::EXC))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextFreeBSD_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 (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU) + sizeof (RegisterContextFreeBSD_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 nullptr;
+ }
+}
+
+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;
+ }
+}
+
+RegisterContextFreeBSD_arm64::RegisterContextFreeBSD_arm64(const lldb_private::ArchSpec &target_arch) :
+ RegisterInfoInterface(target_arch),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch))
+{
+}
+
+size_t
+RegisterContextFreeBSD_arm64::GetGPRSize() const
+{
+ return sizeof(struct RegisterContextFreeBSD_arm64::GPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextFreeBSD_arm64::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextFreeBSD_arm64::GetRegisterCount() const
+{
+ return m_register_info_count;
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h
new file mode 100644
index 000000000000..249027aaa76c
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h
@@ -0,0 +1,78 @@
+//===-- RegisterContextFreeBSD_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_RegisterContextFreeBSD_arm64_H_
+#define liblldb_RegisterContextFreeBSD_arm64_H_
+
+#include "RegisterContextPOSIX.h"
+
+class RegisterContextFreeBSD_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;
+ };
+
+ RegisterContextFreeBSD_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/Utility/RegisterContextFreeBSD_i386.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
index 185ba26944fe..0171da66a199 100644
--- a/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
@@ -45,6 +45,13 @@ struct dbreg {
/* Index 7: debug control */
};
+using FPR_i386 = FXSAVE;
+
+struct UserArea
+{
+ GPR gpr;
+ FPR_i386 i387;
+};
#define DR_SIZE sizeof(uint32_t)
#define DR_OFFSET(reg_index) \
diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
index 257de7198590..34f2d185da8a 100644
--- a/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
@@ -46,19 +46,24 @@ typedef struct _GPR
uint64_t ss;
} GPR;
-struct dbreg {
- uint64_t dr[16]; /* debug registers */
- /* Index 0-3: debug address registers */
- /* Index 4-5: reserved */
- /* Index 6: debug status */
- /* Index 7: debug control */
- /* Index 8-15: reserved */
+struct DBG {
+ uint64_t dr[16]; /* debug registers */
+ /* Index 0-3: debug address registers */
+ /* Index 4-5: reserved */
+ /* Index 6: debug status */
+ /* Index 7: debug control */
+ /* Index 8-15: reserved */
};
-#define DR_SIZE sizeof(uint64_t)
-#define DR_OFFSET(reg_index) \
- (LLVM_EXTENSION offsetof(dbreg, dr[reg_index]))
+struct UserArea
+{
+ GPR gpr;
+ FPR fpr;
+ DBG dbg;
+};
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
//---------------------------------------------------------------------------
// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64 structure.
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
index 1b3a9491d1c8..37b007cfffcf 100644
--- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -38,6 +38,15 @@
using namespace lldb;
using namespace lldb_private;
+static ConstString GetSymbolOrFunctionName(const SymbolContext &sym_ctx)
+{
+ if (sym_ctx.symbol)
+ return sym_ctx.symbol->GetName();
+ else if (sym_ctx.function)
+ return sym_ctx.function->GetName();
+ return ConstString();
+}
+
RegisterContextLLDB::RegisterContextLLDB
(
Thread& thread,
@@ -175,12 +184,12 @@ RegisterContextLLDB::InitializeZerothFrame()
if (m_sym_ctx.symbol)
{
UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'",
- current_pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString());
+ current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
}
else if (m_sym_ctx.function)
{
UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'",
- current_pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.function->GetName().AsCString());
+ current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
}
else
{
@@ -457,12 +466,12 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (m_sym_ctx.symbol)
{
UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'",
- pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString());
+ pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
}
else if (m_sym_ctx.function)
{
UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'",
- pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.function->GetName().AsCString());
+ pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
}
else
{
@@ -500,7 +509,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (decr_pc_and_recompute_addr_range)
{
UnwindLogMsg ("Backing up the pc value of 0x%" PRIx64 " by 1 and re-doing symbol lookup; old symbol was %s",
- pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString());
+ pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
Address temporary_pc;
temporary_pc.SetLoadAddress (pc - 1, &process->GetTarget());
m_sym_ctx.Clear (false);
@@ -514,7 +523,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range))
m_sym_ctx_valid = true;
}
- UnwindLogMsg ("Symbol is now %s", m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString());
+ UnwindLogMsg ("Symbol is now %s", GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
}
// If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function.
@@ -599,7 +608,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa))
{
- UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister());
+ UnwindLogMsg ("failed to get cfa");
m_frame_type = eNotAValidFrame;
return;
}
@@ -683,7 +692,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame ()
if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame)
return unwind_plan_sp;
- unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread);
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (*m_thread.CalculateTarget(), m_thread);
if (unwind_plan_sp)
{
if (unwind_plan_sp->PlanValidAtAddress (m_current_pc))
@@ -846,12 +855,26 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
{
if (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.
- // The assembly profilers work really well with compiler-generated functions but hand-written
- // assembly can be problematic. We'll set the architecture default UnwindPlan as our fallback
- // UnwindPlan in case this doesn't work out when we try to unwind.
- m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ // We probably have an UnwindPlan created by inspecting assembly instructions. The
+ // assembly profilers work really well with compiler-generated functions but hand-
+ // written assembly can be problematic. We set the eh_frame based unwind plan as our
+ // fallback unwind plan if instruction emulation doesn't work out even for non call
+ // sites if it is available and use the architecture default unwind plan if it is
+ // not available. The eh_frame unwind plan is more reliable even on non call sites
+ // then the architecture default plan and for hand written assembly code it is often
+ // written in a way that it valid at all location what helps in the most common
+ // cases when the instruction emulation fails.
+ UnwindPlanSP eh_frame_unwind_plan = func_unwinders_sp->GetEHFrameUnwindPlan (process->GetTarget(), m_current_offset_backed_up_one);
+ if (eh_frame_unwind_plan &&
+ eh_frame_unwind_plan.get() != unwind_plan_sp.get() &&
+ eh_frame_unwind_plan->GetSourceName() != unwind_plan_sp->GetSourceName())
+ {
+ m_fallback_unwind_plan_sp = eh_frame_unwind_plan;
+ }
+ else
+ {
+ m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ }
}
UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
return unwind_plan_sp;
@@ -878,12 +901,25 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
}
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.
- // The assembly profilers work really well with compiler-generated functions but hand-written
- // assembly can be problematic. We'll set the architecture default UnwindPlan as our fallback
- // UnwindPlan in case this doesn't work out when we try to unwind.
- m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ // We probably have an UnwindPlan created by inspecting assembly instructions. The assembly
+ // profilers work really well with compiler-generated functions but hand- written assembly
+ // can be problematic. We set the eh_frame based unwind plan as our fallback unwind plan if
+ // instruction emulation doesn't work out even for non call sites if it is available and use
+ // the architecture default unwind plan if it is not available. The eh_frame unwind plan is
+ // more reliable even on non call sites then the architecture default plan and for hand
+ // written assembly code it is often written in a way that it valid at all location what
+ // helps in the most common cases when the instruction emulation fails.
+ UnwindPlanSP eh_frame_unwind_plan = func_unwinders_sp->GetEHFrameUnwindPlan (process->GetTarget(), m_current_offset_backed_up_one);
+ if (eh_frame_unwind_plan &&
+ eh_frame_unwind_plan.get() != unwind_plan_sp.get() &&
+ eh_frame_unwind_plan->GetSourceName() != unwind_plan_sp->GetSourceName())
+ {
+ m_fallback_unwind_plan_sp = eh_frame_unwind_plan;
+ }
+ else
+ {
+ m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ }
}
if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))
@@ -1394,16 +1430,13 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
if (unwindplan_regloc.IsSame())
{
- if (IsFrameZero ())
- {
- UnwindLogMsg ("could not supply caller's %s (%d) location, IsSame",
- regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
- return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
- }
- else
- {
- return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
- }
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ regloc.location.register_number = regnum.GetAsKind (eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d), saved in register %s (%d)",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
if (unwindplan_regloc.IsCFAPlusOffset())
@@ -1577,7 +1610,7 @@ RegisterContextLLDB::TryFallbackUnwindPlan ()
UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
- if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM)
+ if (active_row && active_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::unspecified)
{
addr_t new_cfa;
if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa)
@@ -1654,7 +1687,7 @@ RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan ()
UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
- if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM)
+ if (active_row && active_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::unspecified)
{
addr_t new_cfa;
if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa)
@@ -1683,57 +1716,90 @@ RegisterContextLLDB::ReadCFAValueForRow (lldb::RegisterKind row_register_kind,
const UnwindPlan::RowSP &row,
addr_t &cfa_value)
{
- RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFARegister());
RegisterValue reg_value;
cfa_value = LLDB_INVALID_ADDRESS;
addr_t cfa_reg_contents;
- if (ReadGPRValue (cfa_reg, cfa_reg_contents))
+ switch (row->GetCFAValue().GetValueType())
{
- if (row->GetCFAType() == UnwindPlan::Row::CFAIsRegisterDereferenced)
+ case UnwindPlan::Row::CFAValue::isRegisterDereferenced:
{
- const RegisterInfo *reg_info = GetRegisterInfoAtIndex (cfa_reg.GetAsKind (eRegisterKindLLDB));
- RegisterValue reg_value;
- if (reg_info)
+ RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFAValue().GetRegisterNumber());
+ if (ReadGPRValue (cfa_reg, cfa_reg_contents))
{
- Error error = ReadRegisterValueFromMemory(reg_info,
- cfa_reg_contents,
- reg_info->byte_size,
- reg_value);
- if (error.Success ())
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (cfa_reg.GetAsKind (eRegisterKindLLDB));
+ RegisterValue reg_value;
+ if (reg_info)
{
- cfa_value = reg_value.GetAsUInt64();
- UnwindLogMsg ("CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 ", CFA value is 0x%" PRIx64,
- cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB),
- cfa_reg_contents, cfa_value);
- return true;
+ Error error = ReadRegisterValueFromMemory(reg_info,
+ cfa_reg_contents,
+ reg_info->byte_size,
+ reg_value);
+ if (error.Success ())
+ {
+ cfa_value = reg_value.GetAsUInt64();
+ UnwindLogMsg ("CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 ", CFA value is 0x%" PRIx64,
+ cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB),
+ cfa_reg_contents, cfa_value);
+ return true;
+ }
+ else
+ {
+ UnwindLogMsg ("Tried to deref reg %s (%d) [0x%" PRIx64 "] but memory read failed.",
+ cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB),
+ cfa_reg_contents);
+ }
}
- else
+ }
+ break;
+ }
+ case UnwindPlan::Row::CFAValue::isRegisterPlusOffset:
+ {
+ RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFAValue().GetRegisterNumber());
+ if (ReadGPRValue (cfa_reg, cfa_reg_contents))
+ {
+ if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || cfa_reg_contents == 1)
{
- UnwindLogMsg ("Tried to deref reg %s (%d) [0x%" PRIx64 "] but memory read failed.",
+ UnwindLogMsg ("Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64,
cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB),
cfa_reg_contents);
+ cfa_reg_contents = LLDB_INVALID_ADDRESS;
+ return false;
}
+ cfa_value = cfa_reg_contents + row->GetCFAValue().GetOffset();
+ UnwindLogMsg ("CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64 ", offset is %d",
+ cfa_value,
+ cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB),
+ cfa_reg_contents, row->GetCFAValue().GetOffset());
+ return true;
}
+ break;
}
- else
+ case UnwindPlan::Row::CFAValue::isDWARFExpression:
{
- if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || cfa_reg_contents == 1)
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ DataExtractor dwarfdata (row->GetCFAValue().GetDWARFExpressionBytes(),
+ row->GetCFAValue().GetDWARFExpressionLength(),
+ process->GetByteOrder(), process->GetAddressByteSize());
+ ModuleSP opcode_ctx;
+ DWARFExpression dwarfexpr (opcode_ctx, dwarfdata, 0, row->GetCFAValue().GetDWARFExpressionLength());
+ dwarfexpr.SetRegisterKind (row_register_kind);
+ Value result;
+ Error error;
+ if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, this, 0, NULL, result, &error))
{
- UnwindLogMsg ("Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64,
- cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB),
- cfa_reg_contents);
- cfa_reg_contents = LLDB_INVALID_ADDRESS;
- return false;
+ cfa_value = result.GetScalar().ULongLong();
+
+ UnwindLogMsg ("CFA value set by DWARF expression is 0x%" PRIx64, cfa_value);
+ return true;
}
- cfa_value = cfa_reg_contents + row->GetCFAOffset ();
- UnwindLogMsg ("CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64 ", offset is %d",
- cfa_value,
- cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB),
- cfa_reg_contents, row->GetCFAOffset ());
- return true;
+ UnwindLogMsg ("Failed to set CFA value via DWARF expression: %s", error.AsCString());
+ break;
}
+ default:
+ return false;
}
return false;
}
diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp
new file mode 100644
index 000000000000..e7784b1712c3
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp
@@ -0,0 +1,87 @@
+//===-- RegisterContextLinux_arm.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_arm.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Based on RegisterContextDarwin_arm.cpp
+#define GPR_OFFSET(idx) ((idx) * 4)
+#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR))
+#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU))
+#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextLinux_arm::DBG, reg) + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC)))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(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 (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC))
+
+//-----------------------------------------------------------------------------
+// Include RegisterInfos_arm to declare our g_register_infos_arm structure.
+//-----------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_ARM_STRUCT
+#include "RegisterInfos_arm.h"
+#undef DECLARE_REGISTER_INFOS_ARM_STRUCT
+
+static const lldb_private::RegisterInfo *
+GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ return g_register_infos_arm;
+ 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::arm:
+ return static_cast<uint32_t>(sizeof(g_register_infos_arm) / sizeof(g_register_infos_arm[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextLinux_arm::RegisterContextLinux_arm(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_arm::GetGPRSize() const
+{
+ return sizeof(struct RegisterContextLinux_arm::GPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextLinux_arm::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextLinux_arm::GetRegisterCount() const
+{
+ return m_register_info_count;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_arm.h b/source/Plugins/Process/Utility/RegisterContextLinux_arm.h
new file mode 100644
index 000000000000..7087eb4c3dcc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_arm.h
@@ -0,0 +1,76 @@
+//===-- RegisterContextLinux_arm.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_arm_h_
+#define liblldb_RegisterContextLinux_arm_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterInfoInterface.h"
+
+class RegisterContextLinux_arm
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+
+ struct GPR
+ {
+ uint32_t r[16]; // R0-R15
+ uint32_t cpsr; // CPSR
+ };
+
+
+ struct QReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ union {
+ uint32_t s[32];
+ uint64_t d[32];
+ QReg q[16]; // the 128-bit NEON registers
+ } floats;
+ uint32_t fpscr;
+ };
+ struct EXC
+ {
+ uint32_t exception;
+ uint32_t fsr; /* Fault status */
+ uint32_t far; /* Virtual Fault Address */
+ };
+
+ struct DBG
+ {
+ uint32_t bvr[16];
+ uint32_t bcr[16];
+ uint32_t wvr[16];
+ uint32_t wcr[16];
+ };
+
+ RegisterContextLinux_arm(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 // liblldb_RegisterContextLinux_arm_h_
+
diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
index b38d6cc60cac..4f6bbc8f8ab8 100644
--- a/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
@@ -66,7 +66,7 @@ struct UserArea
{
GPR regs; // General purpose registers.
int32_t fpvalid; // True if FPU is being used.
- FPR_i386 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.
@@ -112,6 +112,7 @@ RegisterContextLinux_i386::GetRegisterInfo() const
switch (m_target_arch.GetMachine())
{
case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
return g_register_infos_i386;
default:
assert(false && "Unhandled target architecture.");
diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp
new file mode 100644
index 000000000000..948437f51280
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp
@@ -0,0 +1,102 @@
+//===-- RegisterContextLinux_mips.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <vector>
+#include <stddef.h>
+
+// For GDB, GCC and DWARF Register numbers
+#include "RegisterContextLinux_mips.h"
+
+// Internal codes for mips registers
+#include "lldb-mips64-register-enums.h"
+#include "RegisterContext_mips64.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// GP registers
+typedef struct _GPR
+{
+ uint32_t zero;
+ uint32_t r1;
+ uint32_t r2;
+ uint32_t r3;
+ uint32_t r4;
+ uint32_t r5;
+ uint32_t r6;
+ uint32_t r7;
+ uint32_t r8;
+ uint32_t r9;
+ uint32_t r10;
+ uint32_t r11;
+ uint32_t r12;
+ uint32_t r13;
+ uint32_t r14;
+ uint32_t r15;
+ uint32_t r16;
+ uint32_t r17;
+ uint32_t r18;
+ uint32_t r19;
+ uint32_t r20;
+ uint32_t r21;
+ uint32_t r22;
+ uint32_t r23;
+ uint32_t r24;
+ uint32_t r25;
+ uint32_t r26;
+ uint32_t r27;
+ uint32_t gp;
+ uint32_t sp;
+ uint32_t r30;
+ uint32_t ra;
+ uint32_t mullo;
+ uint32_t mulhi;
+ uint32_t pc;
+ uint32_t badvaddr;
+ uint32_t sr;
+ uint32_t cause;
+} GPR;
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_mips to declare our g_register_infos_mips structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_MIPS_STRUCT
+#include "RegisterInfos_mips.h"
+#undef DECLARE_REGISTER_INFOS_MIPS_STRUCT
+
+RegisterContextLinux_mips::RegisterContextLinux_mips(const ArchSpec &target_arch) :
+ RegisterInfoInterface(target_arch)
+{
+}
+
+size_t
+RegisterContextLinux_mips::GetGPRSize() const
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextLinux_mips::GetRegisterInfo() const
+{
+ switch (m_target_arch.GetMachine())
+ {
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return g_register_infos_mips;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+}
+
+uint32_t
+RegisterContextLinux_mips::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_mips) / sizeof (g_register_infos_mips [0]));
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_mips.h b/source/Plugins/Process/Utility/RegisterContextLinux_mips.h
new file mode 100644
index 000000000000..815473e76ddb
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_mips.h
@@ -0,0 +1,32 @@
+//===-- RegisterContextLinux_mips.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_mips_H_
+#define liblldb_RegisterContextLinux_mips_H_
+
+#include "lldb/lldb-private.h"
+#include "RegisterInfoInterface.h"
+
+class RegisterContextLinux_mips
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+ RegisterContextLinux_mips(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+};
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp
new file mode 100644
index 000000000000..a762930e8eb4
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp
@@ -0,0 +1,143 @@
+//===-- RegisterContextLinux_mips64.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 (__mips__)
+
+#include <vector>
+#include <stddef.h>
+
+// For GDB, GCC and DWARF Register numbers
+#include "RegisterContextLinux_mips64.h"
+
+// Internal codes for all mips64 registers
+#include "lldb-mips64-register-enums.h"
+#include "RegisterContext_mips64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// GP registers
+typedef struct _GPR
+{
+ uint64_t zero;
+ uint64_t r1;
+ uint64_t r2;
+ uint64_t r3;
+ uint64_t r4;
+ uint64_t r5;
+ uint64_t r6;
+ uint64_t r7;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t r16;
+ uint64_t r17;
+ uint64_t r18;
+ uint64_t r19;
+ uint64_t r20;
+ uint64_t r21;
+ uint64_t r22;
+ uint64_t r23;
+ uint64_t r24;
+ uint64_t r25;
+ uint64_t r26;
+ uint64_t r27;
+ uint64_t gp;
+ uint64_t sp;
+ uint64_t r30;
+ uint64_t ra;
+ uint64_t mullo;
+ uint64_t mulhi;
+ uint64_t pc;
+ uint64_t badvaddr;
+ uint64_t sr;
+ uint64_t cause;
+ uint64_t ic;
+ uint64_t dummy;
+} GPR;
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_mips64 to declare our g_register_infos_mips64 structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+#include "RegisterInfos_mips64.h"
+#undef DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_mips to declare our g_register_infos_mips structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_MIPS_STRUCT
+#include "RegisterInfos_mips.h"
+#undef DECLARE_REGISTER_INFOS_MIPS_STRUCT
+
+static const RegisterInfo *
+GetRegisterInfoPtr (const ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ return g_register_infos_mips64;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return g_register_infos_mips;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t
+GetRegisterInfoCount (const ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ return static_cast<uint32_t> (sizeof (g_register_infos_mips64) / sizeof (g_register_infos_mips64 [0]));
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return static_cast<uint32_t> (sizeof (g_register_infos_mips) / sizeof (g_register_infos_mips [0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextLinux_mips64::RegisterContextLinux_mips64(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_mips64::GetGPRSize() const
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextLinux_mips64::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextLinux_mips64::GetRegisterCount () const
+{
+ return m_register_info_count;
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h b/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h
new file mode 100644
index 000000000000..546d148eb693
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h
@@ -0,0 +1,40 @@
+//===-- RegisterContextLinux_mips64.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__mips__)
+
+#ifndef liblldb_RegisterContextLinux_mips64_H_
+#define liblldb_RegisterContextLinux_mips64_H_
+
+#include "lldb/lldb-private.h"
+#include "RegisterInfoInterface.h"
+
+class RegisterContextLinux_mips64
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+ RegisterContextLinux_mips64(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
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
index 5c93ebf88faa..c0993b47a126 100644
--- a/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
@@ -46,12 +46,16 @@ typedef struct _GPR
uint64_t gs;
} GPR;
+struct DBG {
+ uint64_t dr[8];
+};
+
struct UserArea
{
GPR gpr; // General purpose registers.
int32_t fpvalid; // True if FPU is being used.
int32_t pad0;
- FXSAVE i387; // General purpose floating point registers (see FPR for extended register sets).
+ FXSAVE fpr; // General purpose floating point registers (see FPR for extended register sets).
uint64_t tsize; // Text segment size.
uint64_t dsize; // Data segment size.
uint64_t ssize; // Stack segment size.
@@ -64,14 +68,15 @@ struct UserArea
FXSAVE* fpstate; // Location of FPR's.
uint64_t magic; // Identifier for core dumps.
char u_comm[32]; // Command causing core dump.
- uint64_t u_debugreg[8]; // Debug registers (DR0 - DR7).
+ DBG dbg; // Debug registers.
uint64_t error_code; // CPU error code.
uint64_t fault_address; // Control register CR3.
};
-#define DR_SIZE sizeof(((UserArea*)NULL)->u_debugreg[0])
+
#define DR_OFFSET(reg_index) \
- (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index]))
+ (LLVM_EXTENSION offsetof(UserArea, dbg) + \
+ LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
//---------------------------------------------------------------------------
// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64 structure.
diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
new file mode 100644
index 000000000000..d306f86256bc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
@@ -0,0 +1,287 @@
+//===-- RegisterContextPOSIX_arm.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_arm.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// arm general purpose registers.
+const uint32_t g_gpr_regnums_arm[] =
+{
+ gpr_r0_arm,
+ gpr_r1_arm,
+ gpr_r2_arm,
+ gpr_r3_arm,
+ gpr_r4_arm,
+ gpr_r5_arm,
+ gpr_r6_arm,
+ gpr_r7_arm,
+ gpr_r8_arm,
+ gpr_r9_arm,
+ gpr_r10_arm,
+ gpr_r11_arm,
+ gpr_r12_arm,
+ gpr_sp_arm,
+ gpr_lr_arm,
+ gpr_pc_arm,
+ gpr_cpsr_arm,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+
+};
+static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == k_num_gpr_registers_arm, \
+ "g_gpr_regnums_arm has wrong number of register infos");
+
+// arm floating point registers.
+static const uint32_t g_fpu_regnums_arm[] =
+{
+ fpu_s0_arm,
+ fpu_s1_arm,
+ fpu_s2_arm,
+ fpu_s3_arm,
+ fpu_s4_arm,
+ fpu_s5_arm,
+ fpu_s6_arm,
+ fpu_s7_arm,
+ fpu_s8_arm,
+ fpu_s9_arm,
+ fpu_s10_arm,
+ fpu_s11_arm,
+ fpu_s12_arm,
+ fpu_s13_arm,
+ fpu_s14_arm,
+ fpu_s15_arm,
+ fpu_s16_arm,
+ fpu_s17_arm,
+ fpu_s18_arm,
+ fpu_s19_arm,
+ fpu_s20_arm,
+ fpu_s21_arm,
+ fpu_s22_arm,
+ fpu_s23_arm,
+ fpu_s24_arm,
+ fpu_s25_arm,
+ fpu_s26_arm,
+ fpu_s27_arm,
+ fpu_s28_arm,
+ fpu_s29_arm,
+ fpu_s30_arm,
+ fpu_s31_arm,
+ fpu_fpscr_arm,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+
+};
+static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \
+ "g_fpu_regnums_arm has wrong number of register infos");
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_register_sets = 2
+};
+
+// Register sets for arm.
+static const lldb_private::RegisterSet
+g_reg_sets_arm[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm }
+};
+
+bool RegisterContextPOSIX_arm::IsGPR(unsigned reg)
+{
+ return reg <= m_reg_info.last_gpr; // GPR's come first.
+}
+
+bool RegisterContextPOSIX_arm::IsFPR(unsigned reg)
+{
+ return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
+}
+
+RegisterContextPOSIX_arm::RegisterContextPOSIX_arm(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::arm:
+ m_reg_info.num_registers = k_num_registers_arm;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_arm;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_arm;
+ m_reg_info.last_gpr = k_last_gpr_arm;
+ m_reg_info.first_fpr = k_first_fpr_arm;
+ m_reg_info.last_fpr = k_last_fpr_arm;
+ m_reg_info.first_fpr_v = fpu_s0_arm;
+ m_reg_info.last_fpr_v = fpu_s31_arm;
+ m_reg_info.gpr_flags = gpr_cpsr_arm;
+ 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_arm::~RegisterContextPOSIX_arm()
+{
+}
+
+void
+RegisterContextPOSIX_arm::Invalidate()
+{
+}
+
+void
+RegisterContextPOSIX_arm::InvalidateAllRegisters()
+{
+}
+
+unsigned
+RegisterContextPOSIX_arm::GetRegisterOffset(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned
+RegisterContextPOSIX_arm::GetRegisterSize(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t
+RegisterContextPOSIX_arm::GetRegisterCount()
+{
+ size_t num_registers = m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers;
+ return num_registers;
+}
+
+size_t
+RegisterContextPOSIX_arm::GetGPRSize()
+{
+ return m_register_info_ap->GetGPRSize ();
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_arm::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_arm::GetRegisterInfoAtIndex(size_t reg)
+{
+ if (reg < m_reg_info.num_registers)
+ return &GetRegisterInfo()[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContextPOSIX_arm::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_arm::GetRegisterSet(size_t set)
+{
+ if (IsRegisterSetAvailable(set))
+ {
+ switch (m_register_info_ap->m_target_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ return &g_reg_sets_arm[set];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+const char *
+RegisterContextPOSIX_arm::GetRegisterName(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+lldb::ByteOrder
+RegisterContextPOSIX_arm::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_arm::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_arm::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_arm.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
new file mode 100644
index 000000000000..a3a2926262f7
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
@@ -0,0 +1,121 @@
+//===-- RegisterContextPOSIX_arm.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_arm_H_
+#define liblldb_RegisterContextPOSIX_arm_H_
+
+#include "lldb/Core/Log.h"
+#include "lldb-arm-register-enums.h"
+#include "RegisterContextPOSIX.h"
+
+class ProcessMonitor;
+
+class RegisterContextPOSIX_arm
+ : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextPOSIX_arm (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ ~RegisterContextPOSIX_arm();
+
+ 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;
+ };
+
+ struct QReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ union {
+ uint32_t s[32];
+ uint64_t d[32];
+ QReg q[16]; // the 128-bit NEON registers
+ } floats;
+ uint32_t fpscr;
+ };
+
+ uint32_t m_gpr_arm[lldb_private::k_num_gpr_registers_arm]; // 32-bit general purpose registers.
+ RegInfo m_reg_info;
+ struct RegisterContextPOSIX_arm::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_arm_H_
+
diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
index ea54a9ad9cf4..96508eafcce2 100644
--- a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
@@ -23,6 +23,9 @@
#include "RegisterContextPOSIX_arm64.h"
#include "Plugins/Process/elf-core/ProcessElfCore.h"
+using namespace lldb;
+using namespace lldb_private;
+
// ARM64 general purpose registers.
const uint32_t g_gpr_regnums_arm64[] =
{
diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
index 3639960ef3de..29e7a7d21e02 100644
--- a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
@@ -11,164 +11,11 @@
#define liblldb_RegisterContextPOSIX_arm64_H_
#include "lldb/Core/Log.h"
+#include "lldb-arm64-register-enums.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
{
@@ -243,9 +90,9 @@ protected:
uint32_t fpcr;
};
- uint64_t m_gpr_arm64[k_num_gpr_registers_arm64]; // 64-bit general purpose registers.
+ uint64_t m_gpr_arm64[lldb_private::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.
+ 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.
diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
index 991179bdec66..2a61685f12ac 100644
--- a/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
@@ -13,59 +13,11 @@
#include "lldb/Core/Log.h"
#include "RegisterContextPOSIX.h"
#include "RegisterContext_mips64.h"
+#include "lldb-mips64-register-enums.h"
-class ProcessMonitor;
+using namespace lldb_private;
-// ---------------------------------------------------------------------------
-// Internal codes for all mips64 registers.
-// ---------------------------------------------------------------------------
-enum
-{
- k_first_gpr_mips64,
- gpr_zero_mips64 = k_first_gpr_mips64,
- gpr_r1_mips64,
- gpr_r2_mips64,
- gpr_r3_mips64,
- gpr_r4_mips64,
- gpr_r5_mips64,
- gpr_r6_mips64,
- gpr_r7_mips64,
- gpr_r8_mips64,
- gpr_r9_mips64,
- gpr_r10_mips64,
- gpr_r11_mips64,
- gpr_r12_mips64,
- gpr_r13_mips64,
- gpr_r14_mips64,
- gpr_r15_mips64,
- gpr_r16_mips64,
- gpr_r17_mips64,
- gpr_r18_mips64,
- gpr_r19_mips64,
- gpr_r20_mips64,
- gpr_r21_mips64,
- gpr_r22_mips64,
- gpr_r23_mips64,
- gpr_r24_mips64,
- gpr_r25_mips64,
- gpr_r26_mips64,
- gpr_r27_mips64,
- gpr_gp_mips64,
- gpr_sp_mips64,
- gpr_r30_mips64,
- gpr_ra_mips64,
- gpr_sr_mips64,
- gpr_mullo_mips64,
- gpr_mulhi_mips64,
- gpr_badvaddr_mips64,
- gpr_cause_mips64,
- gpr_pc_mips64,
- gpr_ic_mips64,
- gpr_dummy_mips64,
-
- k_num_registers_mips64,
- k_num_gpr_registers_mips64 = k_num_registers_mips64
-};
+class ProcessMonitor;
class RegisterContextPOSIX_mips64
: public lldb_private::RegisterContext
diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
index 828fb2571f79..e353e8114765 100644
--- a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
@@ -159,9 +159,10 @@ g_reg_sets_powerpc[k_num_register_sets] =
{ "Altivec/VMX Registers", "vmx", k_num_vmx_registers_powerpc, g_vmx_regnums },
};
+static_assert(k_first_gpr_powerpc == 0, "GPRs must index starting at 0, or fix IsGPR()");
bool RegisterContextPOSIX_powerpc::IsGPR(unsigned reg)
{
- return (reg >= k_first_gpr_powerpc) && (reg <= k_last_gpr_powerpc); // GPR's come first.
+ return (reg <= k_last_gpr_powerpc); // GPR's come first.
}
bool
diff --git a/source/Plugins/Process/Utility/RegisterContext_mips64.h b/source/Plugins/Process/Utility/RegisterContext_mips64.h
index dfd473d7cbec..96ce2a0acc5b 100644
--- a/source/Plugins/Process/Utility/RegisterContext_mips64.h
+++ b/source/Plugins/Process/Utility/RegisterContext_mips64.h
@@ -14,6 +14,84 @@
enum
{
// GP Registers
+ gcc_dwarf_zero_mips = 0,
+ gcc_dwarf_r1_mips,
+ gcc_dwarf_r2_mips,
+ gcc_dwarf_r3_mips,
+ gcc_dwarf_r4_mips,
+ gcc_dwarf_r5_mips,
+ gcc_dwarf_r6_mips,
+ gcc_dwarf_r7_mips,
+ gcc_dwarf_r8_mips,
+ gcc_dwarf_r9_mips,
+ gcc_dwarf_r10_mips,
+ gcc_dwarf_r11_mips,
+ gcc_dwarf_r12_mips,
+ gcc_dwarf_r13_mips,
+ gcc_dwarf_r14_mips,
+ gcc_dwarf_r15_mips,
+ gcc_dwarf_r16_mips,
+ gcc_dwarf_r17_mips,
+ gcc_dwarf_r18_mips,
+ gcc_dwarf_r19_mips,
+ gcc_dwarf_r20_mips,
+ gcc_dwarf_r21_mips,
+ gcc_dwarf_r22_mips,
+ gcc_dwarf_r23_mips,
+ gcc_dwarf_r24_mips,
+ gcc_dwarf_r25_mips,
+ gcc_dwarf_r26_mips,
+ gcc_dwarf_r27_mips,
+ gcc_dwarf_gp_mips,
+ gcc_dwarf_sp_mips,
+ gcc_dwarf_r30_mips,
+ gcc_dwarf_ra_mips,
+ gcc_dwarf_lo_mips,
+ gcc_dwarf_hi_mips,
+ gcc_dwarf_pc_mips,
+ gcc_dwarf_bad_mips,
+ gcc_dwarf_sr_mips,
+ gcc_dwarf_cause_mips,
+ gcc_dwarf_f0_mips,
+ gcc_dwarf_f1_mips,
+ gcc_dwarf_f2_mips,
+ gcc_dwarf_f3_mips,
+ gcc_dwarf_f4_mips,
+ gcc_dwarf_f5_mips,
+ gcc_dwarf_f6_mips,
+ gcc_dwarf_f7_mips,
+ gcc_dwarf_f8_mips,
+ gcc_dwarf_f9_mips,
+ gcc_dwarf_f10_mips,
+ gcc_dwarf_f11_mips,
+ gcc_dwarf_f12_mips,
+ gcc_dwarf_f13_mips,
+ gcc_dwarf_f14_mips,
+ gcc_dwarf_f15_mips,
+ gcc_dwarf_f16_mips,
+ gcc_dwarf_f17_mips,
+ gcc_dwarf_f18_mips,
+ gcc_dwarf_f19_mips,
+ gcc_dwarf_f20_mips,
+ gcc_dwarf_f21_mips,
+ gcc_dwarf_f22_mips,
+ gcc_dwarf_f23_mips,
+ gcc_dwarf_f24_mips,
+ gcc_dwarf_f25_mips,
+ gcc_dwarf_f26_mips,
+ gcc_dwarf_f27_mips,
+ gcc_dwarf_f28_mips,
+ gcc_dwarf_f29_mips,
+ gcc_dwarf_f30_mips,
+ gcc_dwarf_f31_mips,
+ gcc_dwarf_fcsr_mips,
+ gcc_dwarf_fir_mips,
+ gcc_dwarf_ic_mips,
+ gcc_dwarf_dummy_mips
+};
+
+enum
+{
gcc_dwarf_zero_mips64 = 0,
gcc_dwarf_r1_mips64,
gcc_dwarf_r2_mips64,
@@ -52,6 +130,40 @@ enum
gcc_dwarf_bad_mips64,
gcc_dwarf_cause_mips64,
gcc_dwarf_pc_mips64,
+ gcc_dwarf_f0_mips64,
+ gcc_dwarf_f1_mips64,
+ gcc_dwarf_f2_mips64,
+ gcc_dwarf_f3_mips64,
+ gcc_dwarf_f4_mips64,
+ gcc_dwarf_f5_mips64,
+ gcc_dwarf_f6_mips64,
+ gcc_dwarf_f7_mips64,
+ gcc_dwarf_f8_mips64,
+ gcc_dwarf_f9_mips64,
+ gcc_dwarf_f10_mips64,
+ gcc_dwarf_f11_mips64,
+ gcc_dwarf_f12_mips64,
+ gcc_dwarf_f13_mips64,
+ gcc_dwarf_f14_mips64,
+ gcc_dwarf_f15_mips64,
+ gcc_dwarf_f16_mips64,
+ gcc_dwarf_f17_mips64,
+ gcc_dwarf_f18_mips64,
+ gcc_dwarf_f19_mips64,
+ gcc_dwarf_f20_mips64,
+ gcc_dwarf_f21_mips64,
+ gcc_dwarf_f22_mips64,
+ gcc_dwarf_f23_mips64,
+ gcc_dwarf_f24_mips64,
+ gcc_dwarf_f25_mips64,
+ gcc_dwarf_f26_mips64,
+ gcc_dwarf_f27_mips64,
+ gcc_dwarf_f28_mips64,
+ gcc_dwarf_f29_mips64,
+ gcc_dwarf_f30_mips64,
+ gcc_dwarf_f31_mips64,
+ gcc_dwarf_fcsr_mips64,
+ gcc_dwarf_fir_mips64,
gcc_dwarf_ic_mips64,
gcc_dwarf_dummy_mips64
};
@@ -59,6 +171,84 @@ enum
// GDB Register numbers (eRegisterKindGDB)
enum
{
+ gdb_zero_mips = 0,
+ gdb_r1_mips,
+ gdb_r2_mips,
+ gdb_r3_mips,
+ gdb_r4_mips,
+ gdb_r5_mips,
+ gdb_r6_mips,
+ gdb_r7_mips,
+ gdb_r8_mips,
+ gdb_r9_mips,
+ gdb_r10_mips,
+ gdb_r11_mips,
+ gdb_r12_mips,
+ gdb_r13_mips,
+ gdb_r14_mips,
+ gdb_r15_mips,
+ gdb_r16_mips,
+ gdb_r17_mips,
+ gdb_r18_mips,
+ gdb_r19_mips,
+ gdb_r20_mips,
+ gdb_r21_mips,
+ gdb_r22_mips,
+ gdb_r23_mips,
+ gdb_r24_mips,
+ gdb_r25_mips,
+ gdb_r26_mips,
+ gdb_r27_mips,
+ gdb_gp_mips,
+ gdb_sp_mips,
+ gdb_r30_mips,
+ gdb_ra_mips,
+ gdb_lo_mips,
+ gdb_hi_mips,
+ gdb_pc_mips,
+ gdb_bad_mips,
+ gdb_sr_mips,
+ gdb_cause_mips,
+ gdb_f0_mips,
+ gdb_f1_mips,
+ gdb_f2_mips,
+ gdb_f3_mips,
+ gdb_f4_mips,
+ gdb_f5_mips,
+ gdb_f6_mips,
+ gdb_f7_mips,
+ gdb_f8_mips,
+ gdb_f9_mips,
+ gdb_f10_mips,
+ gdb_f11_mips,
+ gdb_f12_mips,
+ gdb_f13_mips,
+ gdb_f14_mips,
+ gdb_f15_mips,
+ gdb_f16_mips,
+ gdb_f17_mips,
+ gdb_f18_mips,
+ gdb_f19_mips,
+ gdb_f20_mips,
+ gdb_f21_mips,
+ gdb_f22_mips,
+ gdb_f23_mips,
+ gdb_f24_mips,
+ gdb_f25_mips,
+ gdb_f26_mips,
+ gdb_f27_mips,
+ gdb_f28_mips,
+ gdb_f29_mips,
+ gdb_f30_mips,
+ gdb_f31_mips,
+ gdb_fcsr_mips,
+ gdb_fir_mips,
+ gdb_ic_mips,
+ gdb_dummy_mips
+};
+
+enum
+{
gdb_zero_mips64 = 0,
gdb_r1_mips64,
gdb_r2_mips64,
@@ -97,8 +287,50 @@ enum
gdb_bad_mips64,
gdb_cause_mips64,
gdb_pc_mips64,
+ gdb_f0_mips64,
+ gdb_f1_mips64,
+ gdb_f2_mips64,
+ gdb_f3_mips64,
+ gdb_f4_mips64,
+ gdb_f5_mips64,
+ gdb_f6_mips64,
+ gdb_f7_mips64,
+ gdb_f8_mips64,
+ gdb_f9_mips64,
+ gdb_f10_mips64,
+ gdb_f11_mips64,
+ gdb_f12_mips64,
+ gdb_f13_mips64,
+ gdb_f14_mips64,
+ gdb_f15_mips64,
+ gdb_f16_mips64,
+ gdb_f17_mips64,
+ gdb_f18_mips64,
+ gdb_f19_mips64,
+ gdb_f20_mips64,
+ gdb_f21_mips64,
+ gdb_f22_mips64,
+ gdb_f23_mips64,
+ gdb_f24_mips64,
+ gdb_f25_mips64,
+ gdb_f26_mips64,
+ gdb_f27_mips64,
+ gdb_f28_mips64,
+ gdb_f29_mips64,
+ gdb_f30_mips64,
+ gdb_f31_mips64,
+ gdb_fcsr_mips64,
+ gdb_fir_mips64,
gdb_ic_mips64,
gdb_dummy_mips64
};
+// FP registers
+struct FPR_mips
+{
+ uint64_t fp_reg[32];
+ uint32_t fcsr; /* FPU status register */
+ uint32_t fir; /* FPU control register */
+};
+
#endif // liblldb_RegisterContext_mips64_H_
diff --git a/source/Plugins/Process/Utility/RegisterInfos_arm.h b/source/Plugins/Process/Utility/RegisterInfos_arm.h
new file mode 100644
index 000000000000..3d144d669415
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterInfos_arm.h
@@ -0,0 +1,303 @@
+//===-- RegisterInfos_arm.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_ARM_STRUCT
+
+#include <stddef.h>
+
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "Utility/ARM_GCC_Registers.h"
+#include "Utility/ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#ifndef GPR_OFFSET
+#error GPR_OFFSET 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 EXC_OFFSET
+#error EXC_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef DBG_OFFSET
+#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_r0 = 0,
+ gpr_r1,
+ gpr_r2,
+ gpr_r3,
+ gpr_r4,
+ gpr_r5,
+ gpr_r6,
+ gpr_r7,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13, gpr_sp = gpr_r13,
+ gpr_r14, gpr_lr = gpr_r14,
+ gpr_r15, gpr_pc = gpr_r15,
+ gpr_cpsr,
+
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+ fpu_fpscr,
+
+ exc_exception,
+ exc_fsr,
+ exc_far,
+
+ 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 RegisterInfo g_register_infos_arm[] = {
+// General purpose registers
+// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== ===============
+{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1, gdb_arm_r0, gpr_r0 }, NULL, NULL},
+{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2, gdb_arm_r1, gpr_r1 }, NULL, NULL},
+{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3, gdb_arm_r2, gpr_r2 }, NULL, NULL},
+{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4, gdb_arm_r3, gpr_r3 }, NULL, NULL},
+{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, gpr_r4 }, NULL, NULL},
+{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, gpr_r5 }, NULL, NULL},
+{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, gpr_r6 }, NULL, NULL},
+{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_INVALID_REGNUM, gdb_arm_r7, gpr_r7 }, NULL, NULL},
+{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, gpr_r8 }, NULL, NULL},
+{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, gpr_r9 }, NULL, NULL},
+{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, gpr_r10 }, NULL, NULL},
+{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, gdb_arm_r11, gpr_r11 }, NULL, NULL},
+{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, gpr_r12 }, NULL, NULL},
+{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, gpr_sp }, NULL, NULL},
+{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, gpr_lr }, NULL, NULL},
+{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, gpr_pc }, NULL, NULL},
+{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, gpr_cpsr }, NULL, NULL},
+
+{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, fpu_s0 }, NULL, NULL},
+{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, fpu_s1 }, NULL, NULL},
+{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, fpu_s2 }, NULL, NULL},
+{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, fpu_s3 }, NULL, NULL},
+{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, fpu_s4 }, NULL, NULL},
+{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, fpu_s5 }, NULL, NULL},
+{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, fpu_s6 }, NULL, NULL},
+{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, fpu_s7 }, NULL, NULL},
+{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, fpu_s8 }, NULL, NULL},
+{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, fpu_s9 }, NULL, NULL},
+{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, fpu_s10 }, NULL, NULL},
+{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, fpu_s11 }, NULL, NULL},
+{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, fpu_s12 }, NULL, NULL},
+{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, fpu_s13 }, NULL, NULL},
+{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, fpu_s14 }, NULL, NULL},
+{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, fpu_s15 }, NULL, NULL},
+{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, fpu_s16 }, NULL, NULL},
+{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, fpu_s17 }, NULL, NULL},
+{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, fpu_s18 }, NULL, NULL},
+{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, fpu_s19 }, NULL, NULL},
+{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, fpu_s20 }, NULL, NULL},
+{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, fpu_s21 }, NULL, NULL},
+{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, fpu_s22 }, NULL, NULL},
+{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, fpu_s23 }, NULL, NULL},
+{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, fpu_s24 }, NULL, NULL},
+{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, fpu_s25 }, NULL, NULL},
+{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, fpu_s26 }, NULL, NULL},
+{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, fpu_s27 }, NULL, NULL},
+{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, fpu_s28 }, NULL, NULL},
+{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, fpu_s29 }, NULL, NULL},
+{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, fpu_s30 }, NULL, NULL},
+{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, fpu_s31 }, NULL, NULL},
+{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, fpu_fpscr }, NULL, NULL},
+
+{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL},
+{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, NULL, NULL},
+{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, 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_ARM_STRUCT
diff --git a/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/source/Plugins/Process/Utility/RegisterInfos_arm64.h
index b687423622a4..0255a3bc7d60 100644
--- a/source/Plugins/Process/Utility/RegisterInfos_arm64.h
+++ b/source/Plugins/Process/Utility/RegisterInfos_arm64.h
@@ -198,14 +198,14 @@ 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},
+{ "x0", NULL, 8, GPR_OFFSET(0), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x0, arm64_dwarf::x0, LLDB_REGNUM_GENERIC_ARG1, arm64_gcc::x0, gpr_x0 }, NULL, NULL},
+{ "x1", NULL, 8, GPR_OFFSET(1), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x1, arm64_dwarf::x1, LLDB_REGNUM_GENERIC_ARG2, arm64_gcc::x1, gpr_x1 }, NULL, NULL},
+{ "x2", NULL, 8, GPR_OFFSET(2), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x2, arm64_dwarf::x2, LLDB_REGNUM_GENERIC_ARG3, arm64_gcc::x2, gpr_x2 }, NULL, NULL},
+{ "x3", NULL, 8, GPR_OFFSET(3), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x3, arm64_dwarf::x3, LLDB_REGNUM_GENERIC_ARG4, arm64_gcc::x3, gpr_x3 }, NULL, NULL},
+{ "x4", NULL, 8, GPR_OFFSET(4), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x4, arm64_dwarf::x4, LLDB_REGNUM_GENERIC_ARG5, arm64_gcc::x4, gpr_x4 }, NULL, NULL},
+{ "x5", NULL, 8, GPR_OFFSET(5), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x5, arm64_dwarf::x5, LLDB_REGNUM_GENERIC_ARG6, arm64_gcc::x5, gpr_x5 }, NULL, NULL},
+{ "x6", NULL, 8, GPR_OFFSET(6), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x6, arm64_dwarf::x6, LLDB_REGNUM_GENERIC_ARG7, arm64_gcc::x6, gpr_x6 }, NULL, NULL},
+{ "x7", NULL, 8, GPR_OFFSET(7), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x7, arm64_dwarf::x7, LLDB_REGNUM_GENERIC_ARG8, 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},
diff --git a/source/Plugins/Process/Utility/RegisterInfos_i386.h b/source/Plugins/Process/Utility/RegisterInfos_i386.h
index fc94b8b2a738..69825362134b 100644
--- a/source/Plugins/Process/Utility/RegisterInfos_i386.h
+++ b/source/Plugins/Process/Utility/RegisterInfos_i386.h
@@ -18,12 +18,16 @@
// Computes the offset of the given FPR in the extended data area.
#define FPR_OFFSET(regname) \
- (LLVM_EXTENSION offsetof(FPR, xstate) + \
- LLVM_EXTENSION offsetof(FXSAVE, regname))
+ (LLVM_EXTENSION offsetof(UserArea, i387) + \
+ LLVM_EXTENSION offsetof(FPR_i386, regname))
// Computes the offset of the YMM register assembled from register halves.
-#define YMM_OFFSET(regname) \
- (LLVM_EXTENSION offsetof(YMM, regname))
+// Based on DNBArchImplI386.cpp from debugserver
+#define YMM_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, i387) + \
+ LLVM_EXTENSION offsetof(FPR, xstate) + \
+ LLVM_EXTENSION offsetof(FXSAVE, xmm[7]) + \
+ sizeof(XMMReg) + (32 * reg_index))
// Number of bytes needed to represent a FPR.
#if !defined(FPR_SIZE)
@@ -70,7 +74,7 @@
// I believe the YMM registers use dwarf_xmm_%_i386 register numbers and then differentiate based on register size.
#define DEFINE_YMM(reg, i) \
- { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \
+ { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(i), \
eEncodingVector, eFormatVectorOfUInt8, \
{ LLDB_INVALID_REGNUM, dwarf_xmm##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##h_i386, lldb_##reg##i##_i386 }, \
NULL, NULL }
diff --git a/source/Plugins/Process/Utility/RegisterInfos_mips.h b/source/Plugins/Process/Utility/RegisterInfos_mips.h
new file mode 100644
index 000000000000..0956b2ca9eca
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterInfos_mips.h
@@ -0,0 +1,122 @@
+//===-- RegisterInfos_mips.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "llvm/Support/Compiler.h"
+
+#include <stddef.h>
+
+#ifdef DECLARE_REGISTER_INFOS_MIPS_STRUCT
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(GPR, regname))
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(FPR_mips, regname))
+
+// 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*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips }, NULL, NULL }
+
+#define DEFINE_FPR(member, reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((FPR_mips*)NULL)->member) / 2, FPR_OFFSET(member), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL }
+
+#define DEFINE_FPR_INFO(member, reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((FPR_mips*)NULL)->member), FPR_OFFSET(member), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL }
+
+// RegisterKind: GCC, DWARF, Generic, GDB, LLDB
+
+static RegisterInfo
+g_register_infos_mips[] =
+{
+ DEFINE_GPR (zero, "zero", gcc_dwarf_zero_mips, gcc_dwarf_zero_mips, LLDB_INVALID_REGNUM, gdb_zero_mips),
+ DEFINE_GPR (r1, "at", gcc_dwarf_r1_mips, gcc_dwarf_r1_mips, LLDB_INVALID_REGNUM, gdb_r1_mips),
+ DEFINE_GPR (r2, NULL, gcc_dwarf_r2_mips, gcc_dwarf_r2_mips, LLDB_INVALID_REGNUM, gdb_r2_mips),
+ DEFINE_GPR (r3, NULL, gcc_dwarf_r3_mips, gcc_dwarf_r3_mips, LLDB_INVALID_REGNUM, gdb_r3_mips),
+ DEFINE_GPR (r4, NULL, gcc_dwarf_r4_mips, gcc_dwarf_r4_mips, LLDB_REGNUM_GENERIC_ARG1, gdb_r4_mips),
+ DEFINE_GPR (r5, NULL, gcc_dwarf_r5_mips, gcc_dwarf_r5_mips, LLDB_REGNUM_GENERIC_ARG2, gdb_r5_mips),
+ DEFINE_GPR (r6, NULL, gcc_dwarf_r6_mips, gcc_dwarf_r6_mips, LLDB_REGNUM_GENERIC_ARG3, gdb_r6_mips),
+ DEFINE_GPR (r7, NULL, gcc_dwarf_r7_mips, gcc_dwarf_r7_mips, LLDB_REGNUM_GENERIC_ARG4, gdb_r7_mips),
+ DEFINE_GPR (r8, NULL, gcc_dwarf_r8_mips, gcc_dwarf_r8_mips, LLDB_INVALID_REGNUM, gdb_r8_mips),
+ DEFINE_GPR (r9, NULL, gcc_dwarf_r9_mips, gcc_dwarf_r9_mips, LLDB_INVALID_REGNUM, gdb_r9_mips),
+ DEFINE_GPR (r10, NULL, gcc_dwarf_r10_mips, gcc_dwarf_r10_mips, LLDB_INVALID_REGNUM, gdb_r10_mips),
+ DEFINE_GPR (r11, NULL, gcc_dwarf_r11_mips, gcc_dwarf_r11_mips, LLDB_INVALID_REGNUM, gdb_r11_mips),
+ DEFINE_GPR (r12, NULL, gcc_dwarf_r12_mips, gcc_dwarf_r12_mips, LLDB_INVALID_REGNUM, gdb_r12_mips),
+ DEFINE_GPR (r13, NULL, gcc_dwarf_r13_mips, gcc_dwarf_r13_mips, LLDB_INVALID_REGNUM, gdb_r13_mips),
+ DEFINE_GPR (r14, NULL, gcc_dwarf_r14_mips, gcc_dwarf_r14_mips, LLDB_INVALID_REGNUM, gdb_r14_mips),
+ DEFINE_GPR (r15, NULL, gcc_dwarf_r15_mips, gcc_dwarf_r15_mips, LLDB_INVALID_REGNUM, gdb_r15_mips),
+ DEFINE_GPR (r16, NULL, gcc_dwarf_r16_mips, gcc_dwarf_r16_mips, LLDB_INVALID_REGNUM, gdb_r16_mips),
+ DEFINE_GPR (r17, NULL, gcc_dwarf_r17_mips, gcc_dwarf_r17_mips, LLDB_INVALID_REGNUM, gdb_r17_mips),
+ DEFINE_GPR (r18, NULL, gcc_dwarf_r18_mips, gcc_dwarf_r18_mips, LLDB_INVALID_REGNUM, gdb_r18_mips),
+ DEFINE_GPR (r19, NULL, gcc_dwarf_r19_mips, gcc_dwarf_r19_mips, LLDB_INVALID_REGNUM, gdb_r19_mips),
+ DEFINE_GPR (r20, NULL, gcc_dwarf_r20_mips, gcc_dwarf_r20_mips, LLDB_INVALID_REGNUM, gdb_r20_mips),
+ DEFINE_GPR (r21, NULL, gcc_dwarf_r21_mips, gcc_dwarf_r21_mips, LLDB_INVALID_REGNUM, gdb_r21_mips),
+ DEFINE_GPR (r22, NULL, gcc_dwarf_r22_mips, gcc_dwarf_r22_mips, LLDB_INVALID_REGNUM, gdb_r22_mips),
+ DEFINE_GPR (r23, NULL, gcc_dwarf_r23_mips, gcc_dwarf_r23_mips, LLDB_INVALID_REGNUM, gdb_r23_mips),
+ DEFINE_GPR (r24, NULL, gcc_dwarf_r24_mips, gcc_dwarf_r24_mips, LLDB_INVALID_REGNUM, gdb_r24_mips),
+ DEFINE_GPR (r25, NULL, gcc_dwarf_r25_mips, gcc_dwarf_r25_mips, LLDB_INVALID_REGNUM, gdb_r25_mips),
+ DEFINE_GPR (r26, NULL, gcc_dwarf_r26_mips, gcc_dwarf_r26_mips, LLDB_INVALID_REGNUM, gdb_r26_mips),
+ DEFINE_GPR (r27, NULL, gcc_dwarf_r27_mips, gcc_dwarf_r27_mips, LLDB_INVALID_REGNUM, gdb_r27_mips),
+ DEFINE_GPR (gp, "gp", gcc_dwarf_gp_mips, gcc_dwarf_gp_mips, LLDB_INVALID_REGNUM, gdb_gp_mips),
+ DEFINE_GPR (sp, "sp", gcc_dwarf_sp_mips, gcc_dwarf_sp_mips, LLDB_REGNUM_GENERIC_SP, gdb_sp_mips),
+ DEFINE_GPR (r30, "fp", gcc_dwarf_r30_mips, gcc_dwarf_r30_mips, LLDB_REGNUM_GENERIC_FP, gdb_r30_mips),
+ DEFINE_GPR (ra, "ra", gcc_dwarf_ra_mips, gcc_dwarf_ra_mips, LLDB_REGNUM_GENERIC_RA, gdb_ra_mips),
+ DEFINE_GPR (mullo, NULL, gcc_dwarf_lo_mips, gcc_dwarf_lo_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR (mulhi, NULL, gcc_dwarf_hi_mips, gcc_dwarf_hi_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR (pc, NULL, gcc_dwarf_pc_mips, gcc_dwarf_pc_mips, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ DEFINE_GPR (badvaddr, NULL, gcc_dwarf_bad_mips, gcc_dwarf_bad_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR (sr, "status", gcc_dwarf_sr_mips, gcc_dwarf_sr_mips, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR (cause, NULL, gcc_dwarf_cause_mips, gcc_dwarf_cause_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR (fp_reg[0], f0, NULL, gcc_dwarf_f0_mips, gcc_dwarf_f0_mips, LLDB_INVALID_REGNUM, gdb_f0_mips),
+ DEFINE_FPR (fp_reg[1], f1, NULL, gcc_dwarf_f1_mips, gcc_dwarf_f1_mips, LLDB_INVALID_REGNUM, gdb_f1_mips),
+ DEFINE_FPR (fp_reg[2], f2, NULL, gcc_dwarf_f2_mips, gcc_dwarf_f2_mips, LLDB_INVALID_REGNUM, gdb_f2_mips),
+ DEFINE_FPR (fp_reg[3], f3, NULL, gcc_dwarf_f3_mips, gcc_dwarf_f3_mips, LLDB_INVALID_REGNUM, gdb_f3_mips),
+ DEFINE_FPR (fp_reg[4], f4, NULL, gcc_dwarf_f4_mips, gcc_dwarf_f4_mips, LLDB_INVALID_REGNUM, gdb_f4_mips),
+ DEFINE_FPR (fp_reg[5], f5, NULL, gcc_dwarf_f5_mips, gcc_dwarf_f5_mips, LLDB_INVALID_REGNUM, gdb_f5_mips),
+ DEFINE_FPR (fp_reg[6], f6, NULL, gcc_dwarf_f6_mips, gcc_dwarf_f6_mips, LLDB_INVALID_REGNUM, gdb_f6_mips),
+ DEFINE_FPR (fp_reg[7], f7, NULL, gcc_dwarf_f7_mips, gcc_dwarf_f7_mips, LLDB_INVALID_REGNUM, gdb_f7_mips),
+ DEFINE_FPR (fp_reg[8], f8, NULL, gcc_dwarf_f8_mips, gcc_dwarf_f8_mips, LLDB_INVALID_REGNUM, gdb_f8_mips),
+ DEFINE_FPR (fp_reg[9], f9, NULL, gcc_dwarf_f9_mips, gcc_dwarf_f9_mips, LLDB_INVALID_REGNUM, gdb_f9_mips),
+ DEFINE_FPR (fp_reg[10], f10, NULL, gcc_dwarf_f10_mips, gcc_dwarf_f10_mips, LLDB_INVALID_REGNUM, gdb_f10_mips),
+ DEFINE_FPR (fp_reg[11], f11, NULL, gcc_dwarf_f11_mips, gcc_dwarf_f11_mips, LLDB_INVALID_REGNUM, gdb_f11_mips),
+ DEFINE_FPR (fp_reg[12], f12, NULL, gcc_dwarf_f12_mips, gcc_dwarf_f12_mips, LLDB_INVALID_REGNUM, gdb_f12_mips),
+ DEFINE_FPR (fp_reg[13], f13, NULL, gcc_dwarf_f13_mips, gcc_dwarf_f13_mips, LLDB_INVALID_REGNUM, gdb_f13_mips),
+ DEFINE_FPR (fp_reg[14], f14, NULL, gcc_dwarf_f14_mips, gcc_dwarf_f14_mips, LLDB_INVALID_REGNUM, gdb_f14_mips),
+ DEFINE_FPR (fp_reg[15], f15, NULL, gcc_dwarf_f15_mips, gcc_dwarf_f15_mips, LLDB_INVALID_REGNUM, gdb_f15_mips),
+ DEFINE_FPR (fp_reg[16], f16, NULL, gcc_dwarf_f16_mips, gcc_dwarf_f16_mips, LLDB_INVALID_REGNUM, gdb_f16_mips),
+ DEFINE_FPR (fp_reg[17], f17, NULL, gcc_dwarf_f17_mips, gcc_dwarf_f17_mips, LLDB_INVALID_REGNUM, gdb_f17_mips),
+ DEFINE_FPR (fp_reg[18], f18, NULL, gcc_dwarf_f18_mips, gcc_dwarf_f18_mips, LLDB_INVALID_REGNUM, gdb_f18_mips),
+ DEFINE_FPR (fp_reg[19], f19, NULL, gcc_dwarf_f19_mips, gcc_dwarf_f19_mips, LLDB_INVALID_REGNUM, gdb_f19_mips),
+ DEFINE_FPR (fp_reg[20], f20, NULL, gcc_dwarf_f20_mips, gcc_dwarf_f20_mips, LLDB_INVALID_REGNUM, gdb_f20_mips),
+ DEFINE_FPR (fp_reg[21], f21, NULL, gcc_dwarf_f21_mips, gcc_dwarf_f21_mips, LLDB_INVALID_REGNUM, gdb_f21_mips),
+ DEFINE_FPR (fp_reg[22], f22, NULL, gcc_dwarf_f22_mips, gcc_dwarf_f22_mips, LLDB_INVALID_REGNUM, gdb_f22_mips),
+ DEFINE_FPR (fp_reg[23], f23, NULL, gcc_dwarf_f23_mips, gcc_dwarf_f23_mips, LLDB_INVALID_REGNUM, gdb_f23_mips),
+ DEFINE_FPR (fp_reg[24], f24, NULL, gcc_dwarf_f24_mips, gcc_dwarf_f24_mips, LLDB_INVALID_REGNUM, gdb_f24_mips),
+ DEFINE_FPR (fp_reg[25], f25, NULL, gcc_dwarf_f25_mips, gcc_dwarf_f25_mips, LLDB_INVALID_REGNUM, gdb_f25_mips),
+ DEFINE_FPR (fp_reg[26], f26, NULL, gcc_dwarf_f26_mips, gcc_dwarf_f26_mips, LLDB_INVALID_REGNUM, gdb_f26_mips),
+ DEFINE_FPR (fp_reg[27], f27, NULL, gcc_dwarf_f27_mips, gcc_dwarf_f27_mips, LLDB_INVALID_REGNUM, gdb_f27_mips),
+ DEFINE_FPR (fp_reg[28], f28, NULL, gcc_dwarf_f28_mips, gcc_dwarf_f28_mips, LLDB_INVALID_REGNUM, gdb_f28_mips),
+ DEFINE_FPR (fp_reg[29], f29, NULL, gcc_dwarf_f29_mips, gcc_dwarf_f29_mips, LLDB_INVALID_REGNUM, gdb_f29_mips),
+ DEFINE_FPR (fp_reg[30], f30, NULL, gcc_dwarf_f30_mips, gcc_dwarf_f30_mips, LLDB_INVALID_REGNUM, gdb_f30_mips),
+ DEFINE_FPR (fp_reg[31], f31, NULL, gcc_dwarf_f31_mips, gcc_dwarf_f31_mips, LLDB_INVALID_REGNUM, gdb_f31_mips),
+ DEFINE_FPR_INFO (fcsr, fcsr, NULL, gcc_dwarf_fcsr_mips, gcc_dwarf_fcsr_mips, LLDB_INVALID_REGNUM, gdb_fcsr_mips),
+ DEFINE_FPR_INFO (fir, fir, NULL, gcc_dwarf_fir_mips, gcc_dwarf_fir_mips, LLDB_INVALID_REGNUM, gdb_fir_mips)
+};
+static_assert((sizeof(g_register_infos_mips) / sizeof(g_register_infos_mips[0])) == k_num_registers_mips,
+ "g_register_infos_mips has wrong number of register infos");
+
+#undef GPR_OFFSET
+#undef FPR_OFFSET
+#undef DEFINE_GPR
+#undef DEFINE_FPR
+
+#endif // DECLARE_REGISTER_INFOS_MIPS_STRUCT
diff --git a/source/Plugins/Process/Utility/RegisterInfos_mips64.h b/source/Plugins/Process/Utility/RegisterInfos_mips64.h
index 187b8e98332e..e03aea4e3f2c 100644
--- a/source/Plugins/Process/Utility/RegisterInfos_mips64.h
+++ b/source/Plugins/Process/Utility/RegisterInfos_mips64.h
@@ -6,20 +6,31 @@
// License. See LICENSE.TXT for details.
//
//===---------------------------------------------------------------------===//
+#include "llvm/Support/Compiler.h"
#include <stddef.h>
+#ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+
// Computes the offset of the given GPR in the user data area.
-#define GPR_OFFSET(regname) \
- (offsetof(GPR, regname))
+#define GPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(GPR, regname))
-#ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ LLVM_EXTENSION offsetof(FPR_mips, regname) \
+
+// RegisterKind: GCC, DWARF, Generic, GDB, LLDB
// 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*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((GPR*)0)->reg), GPR_OFFSET(reg), eEncodingUint, \
eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL }
+#define DEFINE_FPR(member, reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((FPR_mips*)0)->member), FPR_OFFSET(member), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips64 }, NULL, NULL }
+
static RegisterInfo
g_register_infos_mips64[] =
{
@@ -28,14 +39,14 @@ g_register_infos_mips64[] =
DEFINE_GPR(r1, NULL, gcc_dwarf_r1_mips64, gcc_dwarf_r1_mips64, LLDB_INVALID_REGNUM, gdb_r1_mips64),
DEFINE_GPR(r2, NULL, gcc_dwarf_r2_mips64, gcc_dwarf_r2_mips64, LLDB_INVALID_REGNUM, gdb_r2_mips64),
DEFINE_GPR(r3, NULL, gcc_dwarf_r3_mips64, gcc_dwarf_r3_mips64, LLDB_INVALID_REGNUM, gdb_r3_mips64),
- DEFINE_GPR(r4, NULL, gcc_dwarf_r4_mips64, gcc_dwarf_r4_mips64, LLDB_INVALID_REGNUM, gdb_r4_mips64),
- DEFINE_GPR(r5, NULL, gcc_dwarf_r5_mips64, gcc_dwarf_r5_mips64, LLDB_INVALID_REGNUM, gdb_r5_mips64),
- DEFINE_GPR(r6, NULL, gcc_dwarf_r6_mips64, gcc_dwarf_r6_mips64, LLDB_INVALID_REGNUM, gdb_r6_mips64),
- DEFINE_GPR(r7, NULL, gcc_dwarf_r7_mips64, gcc_dwarf_r7_mips64, LLDB_INVALID_REGNUM, gdb_r7_mips64),
- DEFINE_GPR(r8, NULL, gcc_dwarf_r8_mips64, gcc_dwarf_r8_mips64, LLDB_INVALID_REGNUM, gdb_r8_mips64),
- DEFINE_GPR(r9, NULL, gcc_dwarf_r9_mips64, gcc_dwarf_r9_mips64, LLDB_INVALID_REGNUM, gdb_r9_mips64),
- DEFINE_GPR(r10, NULL, gcc_dwarf_r10_mips64, gcc_dwarf_r10_mips64, LLDB_INVALID_REGNUM, gdb_r10_mips64),
- DEFINE_GPR(r11, NULL, gcc_dwarf_r11_mips64, gcc_dwarf_r11_mips64, LLDB_INVALID_REGNUM, gdb_r11_mips64),
+ DEFINE_GPR(r4, NULL, gcc_dwarf_r4_mips64, gcc_dwarf_r4_mips64, LLDB_REGNUM_GENERIC_ARG1, gdb_r4_mips64),
+ DEFINE_GPR(r5, NULL, gcc_dwarf_r5_mips64, gcc_dwarf_r5_mips64, LLDB_REGNUM_GENERIC_ARG2, gdb_r5_mips64),
+ DEFINE_GPR(r6, NULL, gcc_dwarf_r6_mips64, gcc_dwarf_r6_mips64, LLDB_REGNUM_GENERIC_ARG3, gdb_r6_mips64),
+ DEFINE_GPR(r7, NULL, gcc_dwarf_r7_mips64, gcc_dwarf_r7_mips64, LLDB_REGNUM_GENERIC_ARG4, gdb_r7_mips64),
+ DEFINE_GPR(r8, NULL, gcc_dwarf_r8_mips64, gcc_dwarf_r8_mips64, LLDB_REGNUM_GENERIC_ARG5, gdb_r8_mips64),
+ DEFINE_GPR(r9, NULL, gcc_dwarf_r9_mips64, gcc_dwarf_r9_mips64, LLDB_REGNUM_GENERIC_ARG6, gdb_r9_mips64),
+ DEFINE_GPR(r10, NULL, gcc_dwarf_r10_mips64, gcc_dwarf_r10_mips64, LLDB_REGNUM_GENERIC_ARG7, gdb_r10_mips64),
+ DEFINE_GPR(r11, NULL, gcc_dwarf_r11_mips64, gcc_dwarf_r11_mips64, LLDB_REGNUM_GENERIC_ARG8, gdb_r11_mips64),
DEFINE_GPR(r12, NULL, gcc_dwarf_r12_mips64, gcc_dwarf_r12_mips64, LLDB_INVALID_REGNUM, gdb_r12_mips64),
DEFINE_GPR(r13, NULL, gcc_dwarf_r13_mips64, gcc_dwarf_r13_mips64, LLDB_INVALID_REGNUM, gdb_r13_mips64),
DEFINE_GPR(r14, NULL, gcc_dwarf_r14_mips64, gcc_dwarf_r14_mips64, LLDB_INVALID_REGNUM, gdb_r14_mips64),
@@ -54,23 +65,58 @@ g_register_infos_mips64[] =
DEFINE_GPR(r27, NULL, gcc_dwarf_r27_mips64, gcc_dwarf_r27_mips64, LLDB_INVALID_REGNUM, gdb_r27_mips64),
DEFINE_GPR(gp, "r28", gcc_dwarf_gp_mips64, gcc_dwarf_gp_mips64, LLDB_INVALID_REGNUM, gdb_gp_mips64),
DEFINE_GPR(sp, "r29", gcc_dwarf_sp_mips64, gcc_dwarf_sp_mips64, LLDB_REGNUM_GENERIC_SP, gdb_sp_mips64),
- DEFINE_GPR(r30, NULL, gcc_dwarf_r30_mips64, gcc_dwarf_r30_mips64, LLDB_INVALID_REGNUM, gdb_r30_mips64),
- DEFINE_GPR(ra, "r31", gcc_dwarf_ra_mips64, gcc_dwarf_ra_mips64, LLDB_INVALID_REGNUM, gdb_ra_mips64),
- DEFINE_GPR(sr, NULL, gcc_dwarf_sr_mips64, gcc_dwarf_sr_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r30, NULL, gcc_dwarf_r30_mips64, gcc_dwarf_r30_mips64, LLDB_REGNUM_GENERIC_FP, gdb_r30_mips64),
+ DEFINE_GPR(ra, "r31", gcc_dwarf_ra_mips64, gcc_dwarf_ra_mips64, LLDB_REGNUM_GENERIC_RA, gdb_ra_mips64),
DEFINE_GPR(mullo, NULL, gcc_dwarf_lo_mips64, gcc_dwarf_lo_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
DEFINE_GPR(mulhi, NULL, gcc_dwarf_hi_mips64, gcc_dwarf_hi_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(pc, "pc", gcc_dwarf_pc_mips64, gcc_dwarf_pc_mips64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
DEFINE_GPR(badvaddr, NULL, gcc_dwarf_bad_mips64, gcc_dwarf_bad_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(sr, NULL, gcc_dwarf_sr_mips64, gcc_dwarf_sr_mips64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
DEFINE_GPR(cause, NULL, gcc_dwarf_cause_mips64, gcc_dwarf_cause_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(pc, "pc", gcc_dwarf_pc_mips64, gcc_dwarf_pc_mips64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
DEFINE_GPR(ic, NULL, gcc_dwarf_ic_mips64, gcc_dwarf_ic_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
DEFINE_GPR(dummy, NULL, gcc_dwarf_dummy_mips64, gcc_dwarf_dummy_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ DEFINE_FPR (fp_reg[0], f0, NULL, gcc_dwarf_f0_mips64, gcc_dwarf_f0_mips64, LLDB_INVALID_REGNUM, gdb_f0_mips64),
+ DEFINE_FPR (fp_reg[1], f1, NULL, gcc_dwarf_f1_mips64, gcc_dwarf_f1_mips64, LLDB_INVALID_REGNUM, gdb_f1_mips64),
+ DEFINE_FPR (fp_reg[2], f2, NULL, gcc_dwarf_f2_mips64, gcc_dwarf_f2_mips64, LLDB_INVALID_REGNUM, gdb_f2_mips64),
+ DEFINE_FPR (fp_reg[3], f3, NULL, gcc_dwarf_f3_mips64, gcc_dwarf_f3_mips64, LLDB_INVALID_REGNUM, gdb_f3_mips64),
+ DEFINE_FPR (fp_reg[4], f4, NULL, gcc_dwarf_f4_mips64, gcc_dwarf_f4_mips64, LLDB_INVALID_REGNUM, gdb_f4_mips64),
+ DEFINE_FPR (fp_reg[5], f5, NULL, gcc_dwarf_f5_mips64, gcc_dwarf_f5_mips64, LLDB_INVALID_REGNUM, gdb_f5_mips64),
+ DEFINE_FPR (fp_reg[6], f6, NULL, gcc_dwarf_f6_mips64, gcc_dwarf_f6_mips64, LLDB_INVALID_REGNUM, gdb_f6_mips64),
+ DEFINE_FPR (fp_reg[7], f7, NULL, gcc_dwarf_f7_mips64, gcc_dwarf_f7_mips64, LLDB_INVALID_REGNUM, gdb_f7_mips64),
+ DEFINE_FPR (fp_reg[8], f8, NULL, gcc_dwarf_f8_mips64, gcc_dwarf_f8_mips64, LLDB_INVALID_REGNUM, gdb_f8_mips64),
+ DEFINE_FPR (fp_reg[9], f9, NULL, gcc_dwarf_f9_mips64, gcc_dwarf_f9_mips64, LLDB_INVALID_REGNUM, gdb_f9_mips64),
+ DEFINE_FPR (fp_reg[10], f10, NULL, gcc_dwarf_f10_mips64, gcc_dwarf_f10_mips64, LLDB_INVALID_REGNUM, gdb_f10_mips64),
+ DEFINE_FPR (fp_reg[11], f11, NULL, gcc_dwarf_f11_mips64, gcc_dwarf_f11_mips64, LLDB_INVALID_REGNUM, gdb_f11_mips64),
+ DEFINE_FPR (fp_reg[12], f12, NULL, gcc_dwarf_f12_mips64, gcc_dwarf_f12_mips64, LLDB_INVALID_REGNUM, gdb_f12_mips64),
+ DEFINE_FPR (fp_reg[13], f13, NULL, gcc_dwarf_f13_mips64, gcc_dwarf_f13_mips64, LLDB_INVALID_REGNUM, gdb_f13_mips64),
+ DEFINE_FPR (fp_reg[14], f14, NULL, gcc_dwarf_f14_mips64, gcc_dwarf_f14_mips64, LLDB_INVALID_REGNUM, gdb_f14_mips64),
+ DEFINE_FPR (fp_reg[15], f15, NULL, gcc_dwarf_f15_mips64, gcc_dwarf_f15_mips64, LLDB_INVALID_REGNUM, gdb_f15_mips64),
+ DEFINE_FPR (fp_reg[16], f16, NULL, gcc_dwarf_f16_mips64, gcc_dwarf_f16_mips64, LLDB_INVALID_REGNUM, gdb_f16_mips64),
+ DEFINE_FPR (fp_reg[17], f17, NULL, gcc_dwarf_f17_mips64, gcc_dwarf_f17_mips64, LLDB_INVALID_REGNUM, gdb_f17_mips64),
+ DEFINE_FPR (fp_reg[18], f18, NULL, gcc_dwarf_f18_mips64, gcc_dwarf_f18_mips64, LLDB_INVALID_REGNUM, gdb_f18_mips64),
+ DEFINE_FPR (fp_reg[19], f19, NULL, gcc_dwarf_f19_mips64, gcc_dwarf_f19_mips64, LLDB_INVALID_REGNUM, gdb_f19_mips64),
+ DEFINE_FPR (fp_reg[20], f20, NULL, gcc_dwarf_f20_mips64, gcc_dwarf_f20_mips64, LLDB_INVALID_REGNUM, gdb_f20_mips64),
+ DEFINE_FPR (fp_reg[21], f21, NULL, gcc_dwarf_f21_mips64, gcc_dwarf_f21_mips64, LLDB_INVALID_REGNUM, gdb_f21_mips64),
+ DEFINE_FPR (fp_reg[22], f22, NULL, gcc_dwarf_f22_mips64, gcc_dwarf_f22_mips64, LLDB_INVALID_REGNUM, gdb_f22_mips64),
+ DEFINE_FPR (fp_reg[23], f23, NULL, gcc_dwarf_f23_mips64, gcc_dwarf_f23_mips64, LLDB_INVALID_REGNUM, gdb_f23_mips64),
+ DEFINE_FPR (fp_reg[24], f24, NULL, gcc_dwarf_f24_mips64, gcc_dwarf_f24_mips64, LLDB_INVALID_REGNUM, gdb_f24_mips64),
+ DEFINE_FPR (fp_reg[25], f25, NULL, gcc_dwarf_f25_mips64, gcc_dwarf_f25_mips64, LLDB_INVALID_REGNUM, gdb_f25_mips64),
+ DEFINE_FPR (fp_reg[26], f26, NULL, gcc_dwarf_f26_mips64, gcc_dwarf_f26_mips64, LLDB_INVALID_REGNUM, gdb_f26_mips64),
+ DEFINE_FPR (fp_reg[27], f27, NULL, gcc_dwarf_f27_mips64, gcc_dwarf_f27_mips64, LLDB_INVALID_REGNUM, gdb_f27_mips64),
+ DEFINE_FPR (fp_reg[28], f28, NULL, gcc_dwarf_f28_mips64, gcc_dwarf_f28_mips64, LLDB_INVALID_REGNUM, gdb_f28_mips64),
+ DEFINE_FPR (fp_reg[29], f29, NULL, gcc_dwarf_f29_mips64, gcc_dwarf_f29_mips64, LLDB_INVALID_REGNUM, gdb_f29_mips64),
+ DEFINE_FPR (fp_reg[30], f30, NULL, gcc_dwarf_f30_mips64, gcc_dwarf_f30_mips64, LLDB_INVALID_REGNUM, gdb_f30_mips64),
+ DEFINE_FPR (fp_reg[31], f31, NULL, gcc_dwarf_f31_mips64, gcc_dwarf_f31_mips64, LLDB_INVALID_REGNUM, gdb_f31_mips64),
+ DEFINE_FPR (fcsr, fcsr, NULL, gcc_dwarf_fcsr_mips64, gcc_dwarf_fcsr_mips64, LLDB_INVALID_REGNUM, gdb_fcsr_mips64),
+ DEFINE_FPR (fir, fir, NULL, gcc_dwarf_fir_mips64, gcc_dwarf_fir_mips64, LLDB_INVALID_REGNUM, gdb_fir_mips64)
};
static_assert((sizeof(g_register_infos_mips64) / sizeof(g_register_infos_mips64[0])) == k_num_registers_mips64,
"g_register_infos_mips64 has wrong number of register infos");
#undef DEFINE_GPR
-
-#endif // DECLARE_REGISTER_INFOS_MIPS64_STRUCT
-
+#undef DEFINE_FPR
#undef GPR_OFFSET
+#undef FPR_OFFSET
+#endif // DECLARE_REGISTER_INFOS_MIPS64_STRUCT
diff --git a/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
index c1bcd27053c6..5da74ff83487 100644
--- a/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
+++ b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
@@ -16,12 +16,17 @@
// Computes the offset of the given FPR in the extended data area.
#define FPR_OFFSET(regname) \
- (LLVM_EXTENSION offsetof(FPR, xstate) + \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, xstate) + \
LLVM_EXTENSION offsetof(FXSAVE, regname))
// Computes the offset of the YMM register assembled from register halves.
-#define YMM_OFFSET(regname) \
- (LLVM_EXTENSION offsetof(YMM, regname))
+// Based on DNBArchImplX86_64.cpp from debugserver
+#define YMM_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, xstate) + \
+ LLVM_EXTENSION offsetof(XSAVE, ymmh[0]) + \
+ (32 * reg_index))
#ifdef DECLARE_REGISTER_INFOS_X86_64_STRUCT
@@ -37,6 +42,8 @@
// Number of bytes needed to represent a YMM register.
#define YMM_SIZE sizeof(YMMReg)
+#define DR_SIZE sizeof(((DBG*)NULL)->dr[0])
+
// RegisterKind: GCC, DWARF, Generic, GDB, LLDB
// Note that the size and offset will be updated by platform-specific classes.
@@ -67,7 +74,7 @@
NULL, NULL }
#define DEFINE_YMM(reg, i) \
- { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \
+ { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(i), \
eEncodingVector, eFormatVectorOfUInt8, \
{ gcc_dwarf_##reg##i##h_x86_64, gcc_dwarf_##reg##i##h_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##h_x86_64, lldb_##reg##i##_x86_64 }, \
NULL, NULL }
@@ -298,7 +305,7 @@ do {
#define UPDATE_YMM_INFO(reg, i) \
do { \
- g_register_infos[lldb_##reg##i##_i386].byte_offset = YMM_OFFSET(reg[i]); \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = YMM_OFFSET(i); \
} while(false);
#define UPDATE_DR_INFO(reg_index) \
diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp
index a69b38b6c93e..7c68d0d07821 100644
--- a/source/Plugins/Process/Utility/StopInfoMachException.cpp
+++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -498,12 +498,15 @@ StopInfoMachException::CreateStopReasonWithMachException
// If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
// we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
// will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
- if (bp_site_sp->ValidForThisThread (&thread))
+ // If we have an operating system plug-in, we might have set a thread specific breakpoint using the
+ // operating system thread ID, so we can't make any assumptions about the thread ID so we must always
+ // report the breakpoint regardless of the thread.
+ if (bp_site_sp->ValidForThisThread (&thread) || thread.GetProcess()->GetOperatingSystem () != NULL)
return StopInfo::CreateStopReasonWithBreakpointSiteID (thread, bp_site_sp->GetID());
else
return StopInfoSP();
}
-
+
// Don't call this a trace if we weren't single stepping this thread.
if (is_trace_if_actual_breakpoint_missing && thread.GetTemporaryResumeState() == eStateStepping)
{
diff --git a/source/Plugins/Process/Utility/ThreadMemory.cpp b/source/Plugins/Process/Utility/ThreadMemory.cpp
index 56e5a9a59fab..6a7aa626bafc 100644
--- a/source/Plugins/Process/Utility/ThreadMemory.cpp
+++ b/source/Plugins/Process/Utility/ThreadMemory.cpp
@@ -105,7 +105,7 @@ ThreadMemory::CalculateStopInfo ()
if (m_backing_thread_sp)
{
lldb::StopInfoSP backing_stop_info_sp (m_backing_thread_sp->GetPrivateStopInfo());
- if (backing_stop_info_sp)
+ if (backing_stop_info_sp && backing_stop_info_sp->IsValidForOperatingSystemThread(*this))
{
backing_stop_info_sp->SetThread (shared_from_this());
SetStopInfo (backing_stop_info_sp);
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp
index fc592e60d86d..02d3ecd7b3c5 100644
--- a/source/Plugins/Process/Utility/UnwindLLDB.cpp
+++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp
@@ -12,6 +12,7 @@
#include "lldb/Symbol/FuncUnwinders.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Process.h"
diff --git a/source/Plugins/Process/Utility/lldb-arm-register-enums.h b/source/Plugins/Process/Utility/lldb-arm-register-enums.h
new file mode 100644
index 000000000000..a617f6550f65
--- /dev/null
+++ b/source/Plugins/Process/Utility/lldb-arm-register-enums.h
@@ -0,0 +1,153 @@
+//===-- lldb-arm-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_arm_register_enums_h
+#define lldb_arm_register_enums_h
+
+namespace lldb_private
+{
+ // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all ARM registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_arm = 0,
+ gpr_r0_arm = k_first_gpr_arm,
+ gpr_r1_arm,
+ gpr_r2_arm,
+ gpr_r3_arm,
+ gpr_r4_arm,
+ gpr_r5_arm,
+ gpr_r6_arm,
+ gpr_r7_arm,
+ gpr_r8_arm,
+ gpr_r9_arm,
+ gpr_r10_arm,
+ gpr_r11_arm,
+ gpr_r12_arm,
+ gpr_r13_arm, gpr_sp_arm = gpr_r13_arm,
+ gpr_r14_arm, gpr_lr_arm = gpr_r14_arm,
+ gpr_r15_arm, gpr_pc_arm = gpr_r15_arm,
+ gpr_cpsr_arm,
+
+ k_last_gpr_arm = gpr_cpsr_arm,
+
+ k_first_fpr_arm,
+ fpu_s0_arm = k_first_fpr_arm,
+ fpu_s1_arm,
+ fpu_s2_arm,
+ fpu_s3_arm,
+ fpu_s4_arm,
+ fpu_s5_arm,
+ fpu_s6_arm,
+ fpu_s7_arm,
+ fpu_s8_arm,
+ fpu_s9_arm,
+ fpu_s10_arm,
+ fpu_s11_arm,
+ fpu_s12_arm,
+ fpu_s13_arm,
+ fpu_s14_arm,
+ fpu_s15_arm,
+ fpu_s16_arm,
+ fpu_s17_arm,
+ fpu_s18_arm,
+ fpu_s19_arm,
+ fpu_s20_arm,
+ fpu_s21_arm,
+ fpu_s22_arm,
+ fpu_s23_arm,
+ fpu_s24_arm,
+ fpu_s25_arm,
+ fpu_s26_arm,
+ fpu_s27_arm,
+ fpu_s28_arm,
+ fpu_s29_arm,
+ fpu_s30_arm,
+ fpu_s31_arm,
+ fpu_fpscr_arm,
+ k_last_fpr_arm = fpu_fpscr_arm,
+ exc_exception_arm,
+ exc_fsr_arm,
+ exc_far_arm,
+
+ dbg_bvr0_arm,
+ dbg_bvr1_arm,
+ dbg_bvr2_arm,
+ dbg_bvr3_arm,
+ dbg_bvr4_arm,
+ dbg_bvr5_arm,
+ dbg_bvr6_arm,
+ dbg_bvr7_arm,
+ dbg_bvr8_arm,
+ dbg_bvr9_arm,
+ dbg_bvr10_arm,
+ dbg_bvr11_arm,
+ dbg_bvr12_arm,
+ dbg_bvr13_arm,
+ dbg_bvr14_arm,
+ dbg_bvr15_arm,
+ dbg_bcr0_arm,
+ dbg_bcr1_arm,
+ dbg_bcr2_arm,
+ dbg_bcr3_arm,
+ dbg_bcr4_arm,
+ dbg_bcr5_arm,
+ dbg_bcr6_arm,
+ dbg_bcr7_arm,
+ dbg_bcr8_arm,
+ dbg_bcr9_arm,
+ dbg_bcr10_arm,
+ dbg_bcr11_arm,
+ dbg_bcr12_arm,
+ dbg_bcr13_arm,
+ dbg_bcr14_arm,
+ dbg_bcr15_arm,
+ dbg_wvr0_arm,
+ dbg_wvr1_arm,
+ dbg_wvr2_arm,
+ dbg_wvr3_arm,
+ dbg_wvr4_arm,
+ dbg_wvr5_arm,
+ dbg_wvr6_arm,
+ dbg_wvr7_arm,
+ dbg_wvr8_arm,
+ dbg_wvr9_arm,
+ dbg_wvr10_arm,
+ dbg_wvr11_arm,
+ dbg_wvr12_arm,
+ dbg_wvr13_arm,
+ dbg_wvr14_arm,
+ dbg_wvr15_arm,
+ dbg_wcr0_arm,
+ dbg_wcr1_arm,
+ dbg_wcr2_arm,
+ dbg_wcr3_arm,
+ dbg_wcr4_arm,
+ dbg_wcr5_arm,
+ dbg_wcr6_arm,
+ dbg_wcr7_arm,
+ dbg_wcr8_arm,
+ dbg_wcr9_arm,
+ dbg_wcr10_arm,
+ dbg_wcr11_arm,
+ dbg_wcr12_arm,
+ dbg_wcr13_arm,
+ dbg_wcr14_arm,
+ dbg_wcr15_arm,
+
+ k_num_registers_arm,
+ k_num_gpr_registers_arm = k_last_gpr_arm - k_first_gpr_arm + 1,
+ k_num_fpr_registers_arm = k_last_fpr_arm - k_first_fpr_arm + 1
+ };
+}
+
+#endif // #ifndef lldb_arm64_register_enums_h
diff --git a/source/Plugins/Process/Utility/lldb-arm64-register-enums.h b/source/Plugins/Process/Utility/lldb-arm64-register-enums.h
new file mode 100644
index 000000000000..a0c0db0f2786
--- /dev/null
+++ b/source/Plugins/Process/Utility/lldb-arm64-register-enums.h
@@ -0,0 +1,172 @@
+//===-- lldb-arm64-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_arm64_register_enums_h
+#define lldb_arm64_register_enums_h
+
+namespace lldb_private
+{
+ // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+ //---------------------------------------------------------------------------
+ // 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
+ };
+}
+
+#endif // #ifndef lldb_arm64_register_enums_h
diff --git a/source/Plugins/Process/Utility/lldb-mips64-register-enums.h b/source/Plugins/Process/Utility/lldb-mips64-register-enums.h
new file mode 100644
index 000000000000..e8c93a6ec521
--- /dev/null
+++ b/source/Plugins/Process/Utility/lldb-mips64-register-enums.h
@@ -0,0 +1,199 @@
+//===-- lldb-mips64-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_mips64_register_enums_h
+#define lldb_mips64_register_enums_h
+
+namespace lldb_private
+{
+ // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all mips registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_mips,
+ gpr_zero_mips = k_first_gpr_mips,
+ gpr_r1_mips,
+ gpr_r2_mips,
+ gpr_r3_mips,
+ gpr_r4_mips,
+ gpr_r5_mips,
+ gpr_r6_mips,
+ gpr_r7_mips,
+ gpr_r8_mips,
+ gpr_r9_mips,
+ gpr_r10_mips,
+ gpr_r11_mips,
+ gpr_r12_mips,
+ gpr_r13_mips,
+ gpr_r14_mips,
+ gpr_r15_mips,
+ gpr_r16_mips,
+ gpr_r17_mips,
+ gpr_r18_mips,
+ gpr_r19_mips,
+ gpr_r20_mips,
+ gpr_r21_mips,
+ gpr_r22_mips,
+ gpr_r23_mips,
+ gpr_r24_mips,
+ gpr_r25_mips,
+ gpr_r26_mips,
+ gpr_r27_mips,
+ gpr_gp_mips,
+ gpr_sp_mips,
+ gpr_r30_mips,
+ gpr_ra_mips,
+ gpr_mullo_mips,
+ gpr_mulhi_mips,
+ gpr_pc_mips,
+ gpr_badvaddr_mips,
+ gpr_sr_mips,
+ gpr_cause_mips,
+
+ k_last_gpr_mips = gpr_cause_mips,
+
+ k_first_fpr_mips,
+ fpr_f0_mips = k_first_fpr_mips,
+ fpr_f1_mips,
+ fpr_f2_mips,
+ fpr_f3_mips,
+ fpr_f4_mips,
+ fpr_f5_mips,
+ fpr_f6_mips,
+ fpr_f7_mips,
+ fpr_f8_mips,
+ fpr_f9_mips,
+ fpr_f10_mips,
+ fpr_f11_mips,
+ fpr_f12_mips,
+ fpr_f13_mips,
+ fpr_f14_mips,
+ fpr_f15_mips,
+ fpr_f16_mips,
+ fpr_f17_mips,
+ fpr_f18_mips,
+ fpr_f19_mips,
+ fpr_f20_mips,
+ fpr_f21_mips,
+ fpr_f22_mips,
+ fpr_f23_mips,
+ fpr_f24_mips,
+ fpr_f25_mips,
+ fpr_f26_mips,
+ fpr_f27_mips,
+ fpr_f28_mips,
+ fpr_f29_mips,
+ fpr_f30_mips,
+ fpr_f31_mips,
+ fpr_fcsr_mips,
+ fpr_fir_mips,
+ k_last_fpr_mips = fpr_fir_mips,
+
+ k_num_registers_mips,
+ k_num_gpr_registers_mips = k_last_gpr_mips - k_first_gpr_mips + 1,
+ k_num_fpr_registers_mips = k_last_fpr_mips - k_first_fpr_mips + 1,
+ k_num_user_registers_mips = k_num_gpr_registers_mips + k_num_fpr_registers_mips,
+ };
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all mips64 registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_mips64,
+ gpr_zero_mips64 = k_first_gpr_mips64,
+ gpr_r1_mips64,
+ gpr_r2_mips64,
+ gpr_r3_mips64,
+ gpr_r4_mips64,
+ gpr_r5_mips64,
+ gpr_r6_mips64,
+ gpr_r7_mips64,
+ gpr_r8_mips64,
+ gpr_r9_mips64,
+ gpr_r10_mips64,
+ gpr_r11_mips64,
+ gpr_r12_mips64,
+ gpr_r13_mips64,
+ gpr_r14_mips64,
+ gpr_r15_mips64,
+ gpr_r16_mips64,
+ gpr_r17_mips64,
+ gpr_r18_mips64,
+ gpr_r19_mips64,
+ gpr_r20_mips64,
+ gpr_r21_mips64,
+ gpr_r22_mips64,
+ gpr_r23_mips64,
+ gpr_r24_mips64,
+ gpr_r25_mips64,
+ gpr_r26_mips64,
+ gpr_r27_mips64,
+ gpr_gp_mips64,
+ gpr_sp_mips64,
+ gpr_r30_mips64,
+ gpr_ra_mips64,
+ gpr_mullo_mips64,
+ gpr_mulhi_mips64,
+ gpr_pc_mips64,
+ gpr_badvaddr_mips64,
+ gpr_sr_mips64,
+ gpr_cause_mips64,
+ gpr_ic_mips64,
+ gpr_dummy_mips64,
+
+ k_last_gpr_mips64 = gpr_dummy_mips64,
+
+ k_first_fpr_mips64,
+ fpr_f0_mips64 = k_first_fpr_mips64,
+ fpr_f1_mips64,
+ fpr_f2_mips64,
+ fpr_f3_mips64,
+ fpr_f4_mips64,
+ fpr_f5_mips64,
+ fpr_f6_mips64,
+ fpr_f7_mips64,
+ fpr_f8_mips64,
+ fpr_f9_mips64,
+ fpr_f10_mips64,
+ fpr_f11_mips64,
+ fpr_f12_mips64,
+ fpr_f13_mips64,
+ fpr_f14_mips64,
+ fpr_f15_mips64,
+ fpr_f16_mips64,
+ fpr_f17_mips64,
+ fpr_f18_mips64,
+ fpr_f19_mips64,
+ fpr_f20_mips64,
+ fpr_f21_mips64,
+ fpr_f22_mips64,
+ fpr_f23_mips64,
+ fpr_f24_mips64,
+ fpr_f25_mips64,
+ fpr_f26_mips64,
+ fpr_f27_mips64,
+ fpr_f28_mips64,
+ fpr_f29_mips64,
+ fpr_f30_mips64,
+ fpr_f31_mips64,
+ fpr_fcsr_mips64,
+ fpr_fir_mips64,
+ k_last_fpr_mips64 = fpr_fir_mips64,
+
+ k_num_registers_mips64,
+ k_num_gpr_registers_mips64 = k_last_gpr_mips64 - k_first_gpr_mips64 + 1,
+ k_num_fpr_registers_mips64 = k_last_fpr_mips64 - k_first_fpr_mips64 + 1,
+ };
+}
+
+#endif // #ifndef fpr_mips64_register_enums_h
diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index ead959508d88..2fff36dd4ee5 100644
--- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -10,6 +10,9 @@
// C Includes
#include <stdlib.h>
+// C++ Includes
+#include <mutex>
+
// Other libraries and framework includes
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Module.h"
@@ -191,7 +194,7 @@ ProcessElfCore::DoLoadCore ()
const uint32_t num_segments = core->GetProgramHeaderCount();
if (num_segments == 0)
{
- error.SetErrorString ("core file has no sections");
+ error.SetErrorString ("core file has no segments");
return error;
}
@@ -374,13 +377,13 @@ ProcessElfCore::Clear()
void
ProcessElfCore::Initialize()
{
- static bool g_initialized = false;
+ static std::once_flag g_once_flag;
- if (g_initialized == false)
+ std::call_once(g_once_flag, []()
{
- g_initialized = true;
- PluginManager::RegisterPlugin (GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance);
- }
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+ });
}
lldb::addr_t
@@ -424,7 +427,8 @@ ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data,
ArchSpec &arch)
{
lldb::offset_t offset = 0;
- bool lp64 = (arch.GetMachine() == llvm::Triple::mips64 ||
+ bool lp64 = (arch.GetMachine() == llvm::Triple::aarch64 ||
+ arch.GetMachine() == llvm::Triple::mips64 ||
arch.GetMachine() == llvm::Triple::ppc64 ||
arch.GetMachine() == llvm::Triple::x86_64);
int pr_version = data.GetU32(&offset);
diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.h b/source/Plugins/Process/elf-core/ProcessElfCore.h
index 7988bee5ae53..775d9e94dd8e 100644
--- a/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -66,54 +66,42 @@ public:
//------------------------------------------------------------------
// Check if a given Process
//------------------------------------------------------------------
- virtual bool
- CanDebug (lldb_private::Target &target,
- bool plugin_specified_by_name) override;
+ bool CanDebug(lldb_private::Target &target, bool plugin_specified_by_name) override;
//------------------------------------------------------------------
// Creating a new process, or attaching to an existing one
//------------------------------------------------------------------
- virtual lldb_private::Error
- DoLoadCore () override;
+ lldb_private::Error DoLoadCore() override;
- virtual lldb_private::DynamicLoader *
- GetDynamicLoader () override;
+ lldb_private::DynamicLoader *GetDynamicLoader() override;
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
- virtual lldb_private::ConstString
- GetPluginName() override;
+ lldb_private::ConstString GetPluginName() override;
- virtual uint32_t
- GetPluginVersion() override;
+ uint32_t GetPluginVersion() override;
//------------------------------------------------------------------
// Process Control
//------------------------------------------------------------------
- virtual lldb_private::Error
- DoDestroy () override;
+ lldb_private::Error DoDestroy() override;
- virtual void
- RefreshStateAfterStop() override;
+ void RefreshStateAfterStop() override;
//------------------------------------------------------------------
// Process Queries
//------------------------------------------------------------------
- virtual bool
- IsAlive () override;
+ bool IsAlive() override;
//------------------------------------------------------------------
// Process Memory
//------------------------------------------------------------------
- virtual size_t
- ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
+ size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
- virtual size_t
- DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
+ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
- virtual lldb::addr_t
- GetImageInfoAddress () override;
+ lldb::addr_t GetImageInfoAddress() override;
lldb_private::ArchSpec
GetArchitecture();
@@ -126,9 +114,8 @@ protected:
void
Clear ( );
- virtual bool
- UpdateThreadList (lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list) override;
+ bool UpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) override;
private:
//------------------------------------------------------------------
diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
new file mode 100644
index 000000000000..f046c112d8b6
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
@@ -0,0 +1,94 @@
+//===-- RegisterContextCorePOSIX_arm.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/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX.h"
+#include "RegisterContextPOSIXCore_arm.h"
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm(Thread &thread,
+ RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset,
+ const DataExtractor &fpregset)
+ : RegisterContextPOSIX_arm(thread, 0, register_info)
+{
+ m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize()));
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_arm::~RegisterContextCorePOSIX_arm()
+{
+}
+
+bool
+RegisterContextCorePOSIX_arm::ReadGPR()
+{
+ return true;
+}
+
+bool
+RegisterContextCorePOSIX_arm::ReadFPR()
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::WriteGPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::WriteFPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ 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
+RegisterContextCorePOSIX_arm::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::HardwareSingleStep(bool enable)
+{
+ return false;
+}
diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
new file mode 100644
index 000000000000..73e2ef7c3a93
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
@@ -0,0 +1,60 @@
+//===-- RegisterContextCorePOSIX_arm.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_RegisterContextCorePOSIX_arm_H_
+#define liblldb_RegisterContextCorePOSIX_arm_H_
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
+
+class RegisterContextCorePOSIX_arm :
+ public RegisterContextPOSIX_arm
+{
+public:
+ RegisterContextCorePOSIX_arm (lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ const lldb_private::DataExtractor &fpregset);
+
+ ~RegisterContextCorePOSIX_arm();
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual 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);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb_private::DataExtractor m_gpr;
+};
+
+#endif // #ifndef liblldb_RegisterContextCorePOSIX_arm_H_
diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
new file mode 100644
index 000000000000..53c0c83c264a
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
@@ -0,0 +1,94 @@
+//===-- RegisterContextCorePOSIX_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/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX.h"
+#include "RegisterContextPOSIXCore_arm64.h"
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(Thread &thread,
+ RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset,
+ const DataExtractor &fpregset)
+ : RegisterContextPOSIX_arm64(thread, 0, register_info)
+{
+ m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize()));
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64()
+{
+}
+
+bool
+RegisterContextCorePOSIX_arm64::ReadGPR()
+{
+ return true;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::ReadFPR()
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::WriteGPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::WriteFPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ 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
+RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable)
+{
+ return false;
+}
diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
new file mode 100644
index 000000000000..2e1d6b4f9ca8
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
@@ -0,0 +1,60 @@
+//===-- RegisterContextCorePOSIX_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_RegisterContextCorePOSIX_arm64_H_
+#define liblldb_RegisterContextCorePOSIX_arm64_H_
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
+
+class RegisterContextCorePOSIX_arm64 :
+ public RegisterContextPOSIX_arm64
+{
+public:
+ RegisterContextCorePOSIX_arm64 (lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ const lldb_private::DataExtractor &fpregset);
+
+ ~RegisterContextCorePOSIX_arm64();
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual 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);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb_private::DataExtractor m_gpr;
+};
+
+#endif // #ifndef liblldb_RegisterContextCorePOSIX_arm64_H_
diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp
index b16335fb8e1e..2abb6ba5decd 100644
--- a/source/Plugins/Process/elf-core/ThreadElfCore.cpp
+++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp
@@ -16,11 +16,17 @@
#include "ThreadElfCore.h"
#include "ProcessElfCore.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
+#include "RegisterContextPOSIXCore_arm.h"
+#include "RegisterContextPOSIXCore_arm64.h"
#include "RegisterContextPOSIXCore_mips64.h"
#include "RegisterContextPOSIXCore_powerpc.h"
#include "RegisterContextPOSIXCore_x86_64.h"
@@ -97,6 +103,12 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
{
switch (arch.GetMachine())
{
+ case llvm::Triple::aarch64:
+ reg_interface = new RegisterContextFreeBSD_arm64(arch);
+ break;
+ case llvm::Triple::arm:
+ reg_interface = new RegisterContextFreeBSD_arm(arch);
+ break;
case llvm::Triple::ppc:
reg_interface = new RegisterContextFreeBSD_powerpc32(arch);
break;
@@ -122,6 +134,12 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
{
switch (arch.GetMachine())
{
+ case llvm::Triple::arm:
+ reg_interface = new RegisterContextLinux_arm(arch);
+ break;
+ case llvm::Triple::aarch64:
+ reg_interface = new RegisterContextLinux_arm64(arch);
+ break;
case llvm::Triple::x86_64:
reg_interface = new RegisterContextLinux_x86_64(arch);
break;
@@ -144,6 +162,12 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
switch (arch.GetMachine())
{
+ case llvm::Triple::aarch64:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm64 (*this, reg_interface, m_gpregset_data, m_fpregset_data));
+ break;
+ case llvm::Triple::arm:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm (*this, reg_interface, m_gpregset_data, m_fpregset_data));
+ break;
case llvm::Triple::mips64:
m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data));
break;
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index d633b3eaf34c..1af3947a75f3 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -18,6 +18,7 @@
// C++ Includes
// Other libraries and framework includes
#include "lldb/Core/Log.h"
+#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
@@ -38,11 +39,20 @@
#if defined(__APPLE__)
# define DEBUGSERVER_BASENAME "debugserver"
#else
-# define DEBUGSERVER_BASENAME "lldb-gdbserver"
+# define DEBUGSERVER_BASENAME "lldb-server"
+#endif
+
+#if defined (HAVE_LIBCOMPRESSION)
+#include <compression.h>
+#endif
+
+#if defined (HAVE_LIBZ)
+#include <zlib.h>
#endif
using namespace lldb;
using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
GDBRemoteCommunication::History::History (uint32_t size) :
m_packets(),
@@ -93,7 +103,7 @@ GDBRemoteCommunication::History::AddPacket (const std::string &src,
}
void
-GDBRemoteCommunication::History::Dump (lldb_private::Stream &strm) const
+GDBRemoteCommunication::History::Dump (Stream &strm) const
{
const uint32_t size = GetNumPacketsInHistory ();
const uint32_t first_idx = GetFirstSavedPacketIndex ();
@@ -114,7 +124,7 @@ GDBRemoteCommunication::History::Dump (lldb_private::Stream &strm) const
}
void
-GDBRemoteCommunication::History::Dump (lldb_private::Log *log) const
+GDBRemoteCommunication::History::Dump (Log *log) const
{
if (log && !m_dumped_to_log)
{
@@ -142,20 +152,21 @@ GDBRemoteCommunication::History::Dump (lldb_private::Log *log) const
// GDBRemoteCommunication constructor
//----------------------------------------------------------------------
GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name,
- const char *listener_name,
- bool is_platform) :
+ const char *listener_name) :
Communication(comm_name),
#ifdef LLDB_CONFIGURATION_DEBUG
m_packet_timeout (1000),
#else
m_packet_timeout (1),
#endif
+ m_echo_number(0),
+ m_supports_qEcho (eLazyBoolCalculate),
m_sequence_mutex (Mutex::eMutexTypeRecursive),
m_public_is_running (false),
m_private_is_running (false),
m_history (512),
m_send_acks (true),
- m_is_platform (is_platform),
+ m_compression_type (CompressionType::None),
m_listen_url ()
{
}
@@ -169,6 +180,12 @@ GDBRemoteCommunication::~GDBRemoteCommunication()
{
Disconnect();
}
+
+ // Stop the communications read thread which is used to parse all
+ // incoming packets. This function will block until the read
+ // thread returns.
+ if (m_read_thread_enabled)
+ StopReadThread();
}
char
@@ -260,7 +277,7 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le
strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)binary_start_offset, packet_data);
const uint8_t *p;
// Print binary data exactly as sent
- for (p = (uint8_t*)packet_data + binary_start_offset; *p != '#'; ++p)
+ for (p = (const uint8_t*)packet_data + binary_start_offset; *p != '#'; ++p)
strm.Printf("\\x%2.2x", *p);
// Print the checksum
strm.Printf("%*s", (int)3, p);
@@ -293,7 +310,7 @@ GDBRemoteCommunication::PacketResult
GDBRemoteCommunication::GetAck ()
{
StringExtractorGDBRemote packet;
- PacketResult result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ());
+ PacketResult result = ReadPacket (packet, GetPacketTimeoutInMicroSeconds (), false);
if (result == PacketResult::Success)
{
if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck)
@@ -322,7 +339,63 @@ GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
}
GDBRemoteCommunication::PacketResult
-GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec)
+GDBRemoteCommunication::ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout)
+{
+ if (m_read_thread_enabled)
+ return PopPacketFromQueue (response, timeout_usec);
+ else
+ return WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec, sync_on_timeout);
+}
+
+
+// This function is called when a packet is requested.
+// A whole packet is popped from the packet queue and returned to the caller.
+// Packets are placed into this queue from the communication read thread.
+// See GDBRemoteCommunication::AppendBytesToCache.
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec)
+{
+ // Calculate absolute timeout value
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithMicroSeconds(timeout_usec);
+
+ do
+ {
+ // scope for the mutex
+ {
+ // lock down the packet queue
+ Mutex::Locker locker(m_packet_queue_mutex);
+
+ // Wait on condition variable.
+ if (m_packet_queue.size() == 0)
+ m_condition_queue_not_empty.Wait(m_packet_queue_mutex, &timeout);
+
+ if (m_packet_queue.size() > 0)
+ {
+ // get the front element of the queue
+ response = m_packet_queue.front();
+
+ // remove the front element
+ m_packet_queue.pop();
+
+ // we got a packet
+ return PacketResult::Success;
+ }
+ }
+
+ // Disconnected
+ if (!IsConnected())
+ return PacketResult::ErrorDisconnected;
+
+ // Loop while not timed out
+ } while (TimeValue::Now() < timeout);
+
+ return PacketResult::ErrorReplyTimeout;
+}
+
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec, bool sync_on_timeout)
{
uint8_t buffer[8192];
Error error;
@@ -330,7 +403,7 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE));
// Check for a packet from our cache first without trying any reading...
- if (CheckForPacket (NULL, 0, packet))
+ if (CheckForPacket(NULL, 0, packet) != PacketType::Invalid)
return PacketResult::Success;
bool timed_out = false;
@@ -350,7 +423,7 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac
if (bytes_read > 0)
{
- if (CheckForPacket (buffer, bytes_read, packet))
+ if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid)
return PacketResult::Success;
}
else
@@ -359,6 +432,104 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac
{
case eConnectionStatusTimedOut:
case eConnectionStatusInterrupted:
+ if (sync_on_timeout)
+ {
+ //------------------------------------------------------------------
+ /// Sync the remote GDB server and make sure we get a response that
+ /// corresponds to what we send.
+ ///
+ /// Sends a "qEcho" packet and makes sure it gets the exact packet
+ /// echoed back. If the qEcho packet isn't supported, we send a qC
+ /// packet and make sure we get a valid thread ID back. We use the
+ /// "qC" packet since its response if very unique: is responds with
+ /// "QC%x" where %x is the thread ID of the current thread. This
+ /// makes the response unique enough from other packet responses to
+ /// ensure we are back on track.
+ ///
+ /// This packet is needed after we time out sending a packet so we
+ /// can ensure that we are getting the response for the packet we
+ /// are sending. There are no sequence IDs in the GDB remote
+ /// protocol (there used to be, but they are not supported anymore)
+ /// so if you timeout sending packet "abc", you might then send
+ /// packet "cde" and get the response for the previous "abc" packet.
+ /// Many responses are "OK" or "" (unsupported) or "EXX" (error) so
+ /// many responses for packets can look like responses for other
+ /// packets. So if we timeout, we need to ensure that we can get
+ /// back on track. If we can't get back on track, we must
+ /// disconnect.
+ //------------------------------------------------------------------
+ bool sync_success = false;
+ bool got_actual_response = false;
+ // We timed out, we need to sync back up with the
+ char echo_packet[32];
+ int echo_packet_len = 0;
+ RegularExpression response_regex;
+
+ if (m_supports_qEcho == eLazyBoolYes)
+ {
+ echo_packet_len = ::snprintf (echo_packet, sizeof(echo_packet), "qEcho:%u", ++m_echo_number);
+ std::string regex_str = "^";
+ regex_str += echo_packet;
+ regex_str += "$";
+ response_regex.Compile(regex_str.c_str());
+ }
+ else
+ {
+ echo_packet_len = ::snprintf (echo_packet, sizeof(echo_packet), "qC");
+ response_regex.Compile("^QC[0-9A-Fa-f]+$");
+ }
+
+ PacketResult echo_packet_result = SendPacketNoLock (echo_packet, echo_packet_len);
+ if (echo_packet_result == PacketResult::Success)
+ {
+ const uint32_t max_retries = 3;
+ uint32_t successful_responses = 0;
+ for (uint32_t i=0; i<max_retries; ++i)
+ {
+ StringExtractorGDBRemote echo_response;
+ echo_packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (echo_response, timeout_usec, false);
+ if (echo_packet_result == PacketResult::Success)
+ {
+ ++successful_responses;
+ if (response_regex.Execute(echo_response.GetStringRef().c_str()))
+ {
+ sync_success = true;
+ break;
+ }
+ else if (successful_responses == 1)
+ {
+ // We got something else back as the first successful response, it probably is
+ // the response to the packet we actually wanted, so copy it over if this
+ // is the first success and continue to try to get the qEcho response
+ packet = echo_response;
+ got_actual_response = true;
+ }
+ }
+ else if (echo_packet_result == PacketResult::ErrorReplyTimeout)
+ continue; // Packet timed out, continue waiting for a response
+ else
+ break; // Something else went wrong getting the packet back, we failed and are done trying
+ }
+ }
+
+ // We weren't able to sync back up with the server, we must abort otherwise
+ // all responses might not be from the right packets...
+ if (sync_success)
+ {
+ // We timed out, but were able to recover
+ if (got_actual_response)
+ {
+ // We initially timed out, but we did get a response that came in before the successful
+ // reply to our qEcho packet, so lets say everything is fine...
+ return PacketResult::Success;
+ }
+ }
+ else
+ {
+ disconnected = true;
+ Disconnect();
+ }
+ }
timed_out = true;
break;
case eConnectionStatusSuccess:
@@ -385,6 +556,226 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac
}
bool
+GDBRemoteCommunication::DecompressPacket ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+
+ if (!CompressionIsEnabled())
+ return true;
+
+ size_t pkt_size = m_bytes.size();
+ if (pkt_size < 6)
+ return true;
+ if (m_bytes[0] != '$' && m_bytes[0] != '%')
+ return true;
+ if (m_bytes[1] != 'C' && m_bytes[1] != 'N')
+ return true;
+ if (m_bytes[pkt_size - 3] != '#')
+ return true;
+ if (!::isxdigit (m_bytes[pkt_size - 2]) || !::isxdigit (m_bytes[pkt_size - 1]))
+ return true;
+
+ size_t content_length = pkt_size - 5; // not counting '$', 'C' | 'N', '#', & the two hex checksum chars
+ size_t content_start = 2; // The first character of the compressed/not-compressed text of the packet
+ size_t hash_mark_idx = pkt_size - 3; // The '#' character marking the end of the packet
+ size_t checksum_idx = pkt_size - 2; // The first character of the two hex checksum characters
+
+ // Compressed packets ("$C") start with a base10 number which is the size of the uncompressed payload,
+ // then a : and then the compressed data. e.g. $C1024:<binary>#00
+ // Update content_start and content_length to only include the <binary> part of the packet.
+
+ uint64_t decompressed_bufsize = ULONG_MAX;
+ if (m_bytes[1] == 'C')
+ {
+ size_t i = content_start;
+ while (i < hash_mark_idx && isdigit(m_bytes[i]))
+ i++;
+ if (i < hash_mark_idx && m_bytes[i] == ':')
+ {
+ i++;
+ content_start = i;
+ content_length = hash_mark_idx - content_start;
+ std::string bufsize_str (m_bytes.data() + 2, i - 2 - 1);
+ errno = 0;
+ decompressed_bufsize = ::strtoul (bufsize_str.c_str(), NULL, 10);
+ if (errno != 0 || decompressed_bufsize == ULONG_MAX)
+ {
+ m_bytes.erase (0, pkt_size);
+ return false;
+ }
+ }
+ }
+
+ if (GetSendAcks ())
+ {
+ char packet_checksum_cstr[3];
+ packet_checksum_cstr[0] = m_bytes[checksum_idx];
+ packet_checksum_cstr[1] = m_bytes[checksum_idx + 1];
+ packet_checksum_cstr[2] = '\0';
+ long packet_checksum = strtol (packet_checksum_cstr, NULL, 16);
+
+ long actual_checksum = CalculcateChecksum (m_bytes.data() + 1, hash_mark_idx - 1);
+ bool success = packet_checksum == actual_checksum;
+ if (!success)
+ {
+ if (log)
+ log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x",
+ (int)(pkt_size),
+ m_bytes.c_str(),
+ (uint8_t)packet_checksum,
+ (uint8_t)actual_checksum);
+ }
+ // Send the ack or nack if needed
+ if (!success)
+ {
+ SendNack();
+ m_bytes.erase (0, pkt_size);
+ return false;
+ }
+ else
+ {
+ SendAck();
+ }
+ }
+
+ if (m_bytes[1] == 'N')
+ {
+ // This packet was not compressed -- delete the 'N' character at the
+ // start and the packet may be processed as-is.
+ m_bytes.erase(1, 1);
+ return true;
+ }
+
+ // Reverse the gdb-remote binary escaping that was done to the compressed text to
+ // guard characters like '$', '#', '}', etc.
+ std::vector<uint8_t> unescaped_content;
+ unescaped_content.reserve (content_length);
+ size_t i = content_start;
+ while (i < hash_mark_idx)
+ {
+ if (m_bytes[i] == '}')
+ {
+ i++;
+ unescaped_content.push_back (m_bytes[i] ^ 0x20);
+ }
+ else
+ {
+ unescaped_content.push_back (m_bytes[i]);
+ }
+ i++;
+ }
+
+ uint8_t *decompressed_buffer = nullptr;
+ size_t decompressed_bytes = 0;
+
+ if (decompressed_bufsize != ULONG_MAX)
+ {
+ decompressed_buffer = (uint8_t *) malloc (decompressed_bufsize + 1);
+ if (decompressed_buffer == nullptr)
+ {
+ m_bytes.erase (0, pkt_size);
+ return false;
+ }
+
+ }
+
+#if defined (HAVE_LIBCOMPRESSION)
+ // libcompression is weak linked so check that compression_decode_buffer() is available
+ if (compression_decode_buffer != NULL &&
+ (m_compression_type == CompressionType::ZlibDeflate
+ || m_compression_type == CompressionType::LZFSE
+ || m_compression_type == CompressionType::LZ4))
+ {
+ compression_algorithm compression_type;
+ if (m_compression_type == CompressionType::ZlibDeflate)
+ compression_type = COMPRESSION_ZLIB;
+ else if (m_compression_type == CompressionType::LZFSE)
+ compression_type = COMPRESSION_LZFSE;
+ else if (m_compression_type == CompressionType::LZ4)
+ compression_type = COMPRESSION_LZ4_RAW;
+ else if (m_compression_type == CompressionType::LZMA)
+ compression_type = COMPRESSION_LZMA;
+
+
+ // If we have the expected size of the decompressed payload, we can allocate
+ // the right-sized buffer and do it. If we don't have that information, we'll
+ // need to try decoding into a big buffer and if the buffer wasn't big enough,
+ // increase it and try again.
+
+ if (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr)
+ {
+ decompressed_bytes = compression_decode_buffer (decompressed_buffer, decompressed_bufsize + 10 ,
+ (uint8_t*) unescaped_content.data(),
+ unescaped_content.size(),
+ NULL,
+ compression_type);
+ }
+ }
+#endif
+
+#if defined (HAVE_LIBZ)
+ if (decompressed_bytes == 0
+ && decompressed_bufsize != ULONG_MAX
+ && decompressed_buffer != nullptr
+ && m_compression_type == CompressionType::ZlibDeflate)
+ {
+ z_stream stream;
+ memset (&stream, 0, sizeof (z_stream));
+ stream.next_in = (Bytef *) unescaped_content.data();
+ stream.avail_in = (uInt) unescaped_content.size();
+ stream.total_in = 0;
+ stream.next_out = (Bytef *) decompressed_buffer;
+ stream.avail_out = decompressed_bufsize;
+ stream.total_out = 0;
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+ stream.opaque = Z_NULL;
+
+ if (inflateInit2 (&stream, -15) == Z_OK)
+ {
+ int status = inflate (&stream, Z_NO_FLUSH);
+ inflateEnd (&stream);
+ if (status == Z_STREAM_END)
+ {
+ decompressed_bytes = stream.total_out;
+ }
+ }
+ }
+#endif
+
+ if (decompressed_bytes == 0 || decompressed_buffer == nullptr)
+ {
+ if (decompressed_buffer)
+ free (decompressed_buffer);
+ m_bytes.erase (0, pkt_size);
+ return false;
+ }
+
+ std::string new_packet;
+ new_packet.reserve (decompressed_bytes + 6);
+ new_packet.push_back (m_bytes[0]);
+ new_packet.append ((const char *) decompressed_buffer, decompressed_bytes);
+ new_packet.push_back ('#');
+ if (GetSendAcks ())
+ {
+ uint8_t decompressed_checksum = CalculcateChecksum ((const char *) decompressed_buffer, decompressed_bytes);
+ char decompressed_checksum_str[3];
+ snprintf (decompressed_checksum_str, 3, "%02x", decompressed_checksum);
+ new_packet.append (decompressed_checksum_str);
+ }
+ else
+ {
+ new_packet.push_back ('0');
+ new_packet.push_back ('0');
+ }
+
+ m_bytes = new_packet;
+
+ free (decompressed_buffer);
+ return true;
+}
+
+GDBRemoteCommunication::PacketType
GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet)
{
// Put the packet data into the buffer in a thread safe fashion
@@ -406,6 +797,8 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
m_bytes.append ((const char *)src, src_len);
}
+ bool isNotifyPacket = false;
+
// Parse up the packets into gdb remote packets
if (!m_bytes.empty())
{
@@ -417,6 +810,17 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
size_t total_length = 0;
size_t checksum_idx = std::string::npos;
+ // Size of packet before it is decompressed, for logging purposes
+ size_t original_packet_size = m_bytes.size();
+ if (CompressionIsEnabled())
+ {
+ if (DecompressPacket() == false)
+ {
+ packet.Clear();
+ return GDBRemoteCommunication::PacketType::Standard;
+ }
+ }
+
switch (m_bytes[0])
{
case '+': // Look for ack
@@ -425,6 +829,10 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
content_length = total_length = 1; // The command is one byte long...
break;
+ case '%': // Async notify packet
+ isNotifyPacket = true;
+ // Intentional fall through
+
case '$':
// Look for a standard gdb packet?
{
@@ -467,6 +875,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
case '+':
case '-':
case '\x03':
+ case '%':
case '$':
done = true;
break;
@@ -486,7 +895,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
if (content_length == std::string::npos)
{
packet.Clear();
- return false;
+ return GDBRemoteCommunication::PacketType::Invalid;
}
else if (total_length > 0)
{
@@ -495,12 +904,10 @@ 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;
+ size_t content_end = content_start + content_length;
bool success = true;
std::string &packet_str = packet.GetStringRef();
-
-
if (log)
{
// If logging was just enabled and we have history, then dump out what
@@ -524,7 +931,10 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
{
StreamString strm;
// Packet header...
- strm.Printf("<%4" PRIu64 "> read packet: %c", (uint64_t)total_length, m_bytes[0]);
+ if (CompressionIsEnabled())
+ strm.Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %c", (uint64_t) original_packet_size, (uint64_t)total_length, m_bytes[0]);
+ else
+ 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...
@@ -547,7 +957,10 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
}
else
{
- log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str());
+ if (CompressionIsEnabled())
+ log->Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %.*s", (uint64_t) original_packet_size, (uint64_t)total_length, (int)(total_length), m_bytes.c_str());
+ else
+ log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str());
}
}
@@ -587,7 +1000,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
}
}
- if (m_bytes[0] == '$')
+ if (m_bytes[0] == '$' || m_bytes[0] == '%')
{
assert (checksum_idx < m_bytes.size());
if (::isxdigit (m_bytes[checksum_idx+0]) ||
@@ -625,11 +1038,15 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
m_bytes.erase(0, total_length);
packet.SetFilePos(0);
- return success;
+
+ if (isNotifyPacket)
+ return GDBRemoteCommunication::PacketType::Notify;
+ else
+ return GDBRemoteCommunication::PacketType::Standard;
}
}
packet.Clear();
- return false;
+ return GDBRemoteCommunication::PacketType::Invalid;
}
Error
@@ -681,7 +1098,7 @@ GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg)
Error
GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
uint16_t in_port,
- lldb_private::ProcessLaunchInfo &launch_info,
+ ProcessLaunchInfo &launch_info,
uint16_t &out_port)
{
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
@@ -741,10 +1158,15 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
Args &debugserver_args = launch_info.GetArguments();
debugserver_args.Clear();
char arg_cstr[PATH_MAX];
-
+
// Start args with "debugserver /file/path -r --"
debugserver_args.AppendArgument(debugserver_path);
+#if !defined(__APPLE__)
+ // First argument to lldb-server must be mode in which to run.
+ debugserver_args.AppendArgument("gdbserver");
+#endif
+
// If a host and port is supplied then use it
char host_and_port[128];
if (hostname)
@@ -766,28 +1188,42 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
}
llvm::SmallString<PATH_MAX> named_pipe_path;
- Pipe port_named_pipe;
+ Pipe port_pipe;
- bool listen = false;
- if (host_and_port[0])
+ if (host_and_port[0] && in_port == 0)
{
// Create a temporary file to get the stdout/stderr and redirect the
// 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"
- if (in_port == 0)
+ // Binding to port zero, we need to figure out what port it ends up
+ // using using a named pipe...
+ error = port_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path);
+ if (error.Success())
{
- // Binding to port zero, we need to figure out what port it ends up
- // using using a named pipe...
- error = port_named_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path);
- if (error.Fail())
- return error;
debugserver_args.AppendArgument("--named-pipe");
debugserver_args.AppendArgument(named_pipe_path.c_str());
}
else
{
- listen = true;
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() "
+ "named pipe creation failed: %s",
+ __FUNCTION__, error.AsCString());
+ // let's try an unnamed pipe
+ error = port_pipe.CreateNew(true);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() "
+ "unnamed pipe creation failed: %s",
+ __FUNCTION__, error.AsCString());
+ return error;
+ }
+ int write_fd = port_pipe.GetWriteFileDescriptor();
+ debugserver_args.AppendArgument("--pipe");
+ debugserver_args.AppendArgument(std::to_string(write_fd).c_str());
+ launch_info.AppendCloseFileAction(port_pipe.GetReadFileDescriptor());
}
}
else
@@ -796,7 +1232,11 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
// connect to us..
error = StartListenThread ("127.0.0.1", 0);
if (error.Fail())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() unable to start listen thread: %s", __FUNCTION__, error.AsCString());
return error;
+ }
ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection ();
// Wait for 10 seconds to resolve the bound port
@@ -813,6 +1253,8 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
else
{
error.SetErrorString ("failed to bind to port 0 on 127.0.0.1");
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString());
return error;
}
}
@@ -824,12 +1266,21 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
debugserver_args.AppendArgument(arg_cstr);
}
+#if defined(__APPLE__)
const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
if (env_debugserver_log_flags)
{
::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
debugserver_args.AppendArgument(arg_cstr);
}
+#else
+ const char *env_debugserver_log_channels = getenv("LLDB_SERVER_LOG_CHANNELS");
+ if (env_debugserver_log_channels)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-channels=%s", env_debugserver_log_channels);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+#endif
// Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back.
uint32_t env_var_index = 1;
@@ -865,56 +1316,70 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
{
if (named_pipe_path.size() > 0)
{
- error = port_named_pipe.OpenAsReader(named_pipe_path, false);
+ error = port_pipe.OpenAsReader(named_pipe_path, false);
+ if (error.Fail())
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() "
+ "failed to open named pipe %s for reading: %s",
+ __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
+ }
+
+ if (port_pipe.CanWrite())
+ port_pipe.CloseWriteFileDescriptor();
+ if (port_pipe.CanRead())
+ {
+ char port_cstr[256];
+ port_cstr[0] = '\0';
+ size_t num_bytes = sizeof(port_cstr);
+ // Read port from pipe with 10 second timeout.
+ error = port_pipe.ReadWithTimeout(port_cstr, num_bytes,
+ std::chrono::seconds{10}, num_bytes);
if (error.Success())
{
- char port_cstr[256];
- port_cstr[0] = '\0';
- size_t num_bytes = sizeof(port_cstr);
- // Read port from pipe with 10 second timeout.
- error = port_named_pipe.ReadWithTimeout(port_cstr, num_bytes, std::chrono::microseconds(10 * 1000000), num_bytes);
- if (error.Success())
- {
- assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0');
- out_port = StringConvert::ToUInt32(port_cstr, 0);
- if (log)
- log->Printf("GDBRemoteCommunication::%s() debugserver listens %u port", __FUNCTION__, out_port);
- }
- else
- {
- if (log)
- log->Printf("GDBRemoteCommunication::%s() failed to read a port value from named pipe %s: %s", __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
-
- }
- port_named_pipe.Close();
+ assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0');
+ out_port = StringConvert::ToUInt32(port_cstr, 0);
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() "
+ "debugserver listens %u port",
+ __FUNCTION__, out_port);
}
else
{
if (log)
- log->Printf("GDBRemoteCommunication::%s() failed to open named pipe %s for reading: %s", __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
+ log->Printf("GDBRemoteCommunication::%s() "
+ "failed to read a port value from pipe %s: %s",
+ __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
+
}
- const auto err = port_named_pipe.Delete(named_pipe_path);
+ port_pipe.Close();
+ }
+
+ if (named_pipe_path.size() > 0)
+ {
+ const auto err = port_pipe.Delete(named_pipe_path);
if (err.Fail())
{
if (log)
- log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s", __FUNCTION__, named_pipe_path.c_str(), err.AsCString());
+ log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s",
+ __FUNCTION__, named_pipe_path.c_str(), err.AsCString());
}
}
- else if (listen)
- {
-
- }
- else
- {
- // Make sure we actually connect with the debugserver...
- JoinListenThread();
- }
+
+ // Make sure we actually connect with the debugserver...
+ JoinListenThread();
}
}
else
{
error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME );
}
+
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString());
+ }
+
return error;
}
@@ -923,3 +1388,65 @@ GDBRemoteCommunication::DumpHistory(Stream &strm)
{
m_history.Dump (strm);
}
+
+GDBRemoteCommunication::ScopedTimeout::ScopedTimeout (GDBRemoteCommunication& gdb_comm,
+ uint32_t timeout) :
+ m_gdb_comm (gdb_comm)
+{
+ m_saved_timeout = m_gdb_comm.SetPacketTimeout (timeout);
+}
+
+GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout ()
+{
+ m_gdb_comm.SetPacketTimeout (m_saved_timeout);
+}
+
+// This function is called via the Communications class read thread when bytes become available
+// for this connection. This function will consume all incoming bytes and try to parse whole
+// packets as they become available. Full packets are placed in a queue, so that all packet
+// requests can simply pop from this queue. Async notification packets will be dispatched
+// immediately to the ProcessGDBRemote Async thread via an event.
+void GDBRemoteCommunication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, lldb::ConnectionStatus status)
+{
+ StringExtractorGDBRemote packet;
+
+ while (true)
+ {
+ PacketType type = CheckForPacket(bytes, len, packet);
+
+ // scrub the data so we do not pass it back to CheckForPacket
+ // on future passes of the loop
+ bytes = nullptr;
+ len = 0;
+
+ // we may have received no packet so lets bail out
+ if (type == PacketType::Invalid)
+ break;
+
+ if (type == PacketType::Standard)
+ {
+ // scope for the mutex
+ {
+ // lock down the packet queue
+ Mutex::Locker locker(m_packet_queue_mutex);
+ // push a new packet into the queue
+ m_packet_queue.push(packet);
+ // Signal condition variable that we have a packet
+ m_condition_queue_not_empty.Signal();
+
+ }
+ }
+
+ if (type == PacketType::Notify)
+ {
+ // put this packet into an event
+ const char *pdata = packet.GetStringRef().c_str();
+
+ // as the communication class, we are a broadcaster and the
+ // async thread is tuned to listen to us
+ BroadcastEvent(
+ eBroadcastBitGdbReadThreadGotNotify,
+ new EventDataBytes(pdata));
+ }
+ }
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
index ee2f3276513d..7379bb3aa09b 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -14,6 +14,7 @@
// C++ Includes
#include <list>
#include <string>
+#include <queue>
// Other libraries and framework includes
// Project includes
@@ -27,6 +28,9 @@
#include "Utility/StringExtractorGDBRemote.h"
+namespace lldb_private {
+namespace process_gdb_remote {
+
typedef enum
{
eStoppointInvalid = -1,
@@ -37,16 +41,33 @@ typedef enum
eWatchpointReadWrite
} GDBStoppointType;
+enum class CompressionType
+{
+ None = 0, // no compression
+ ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's libcompression
+ LZFSE, // an Apple compression scheme, requires Apple's libcompression
+ LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with https://code.google.com/p/lz4/
+ LZMA, // Lempel–Ziv–Markov chain algorithm
+};
+
class ProcessGDBRemote;
-class GDBRemoteCommunication : public lldb_private::Communication
+class GDBRemoteCommunication : public Communication
{
public:
enum
{
- eBroadcastBitRunPacketSent = kLoUserBroadcastBit
+ eBroadcastBitRunPacketSent = kLoUserBroadcastBit,
+ eBroadcastBitGdbReadThreadGotNotify = kLoUserBroadcastBit << 1 // Sent when we received a notify packet.
};
-
+
+ enum class PacketType
+ {
+ Invalid = 0,
+ Standard,
+ Notify
+ };
+
enum class PacketResult
{
Success = 0, // Success
@@ -59,12 +80,25 @@ public:
ErrorDisconnected, // We were disconnected
ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet request
};
+
+ // Class to change the timeout for a given scope and restore it to the original value when the
+ // created ScopedTimeout object got out of scope
+ class ScopedTimeout
+ {
+ public:
+ ScopedTimeout (GDBRemoteCommunication& gdb_comm, uint32_t timeout);
+ ~ScopedTimeout ();
+
+ private:
+ GDBRemoteCommunication& m_gdb_comm;
+ uint32_t m_saved_timeout;
+ };
+
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
GDBRemoteCommunication(const char *comm_name,
- const char *listener_name,
- bool is_platform);
+ const char *listener_name);
virtual
~GDBRemoteCommunication();
@@ -83,9 +117,9 @@ public:
size_t payload_length);
bool
- GetSequenceMutex (lldb_private::Mutex::Locker& locker, const char *failure_message = NULL);
+ GetSequenceMutex (Mutex::Locker& locker, const char *failure_message = NULL);
- bool
+ PacketType
CheckForPacket (const uint8_t *src,
size_t src_len,
StringExtractorGDBRemote &packet);
@@ -126,20 +160,20 @@ public:
uint32_t
GetPacketTimeoutInMicroSeconds () const
{
- return m_packet_timeout * lldb_private::TimeValue::MicroSecPerSec;
+ return m_packet_timeout * TimeValue::MicroSecPerSec;
}
//------------------------------------------------------------------
// Start a debugserver instance on the current host using the
// supplied connection URL.
//------------------------------------------------------------------
- lldb_private::Error
+ Error
StartDebugserverProcess (const char *hostname,
uint16_t in_port, // If set to zero, then out_port will contain the bound port on exit
- lldb_private::ProcessLaunchInfo &launch_info,
+ ProcessLaunchInfo &launch_info,
uint16_t &out_port);
void
- DumpHistory(lldb_private::Stream &strm);
+ DumpHistory(Stream &strm);
protected:
@@ -196,10 +230,10 @@ protected:
uint32_t bytes_transmitted);
void
- Dump (lldb_private::Stream &strm) const;
+ Dump (Stream &strm) const;
void
- Dump (lldb_private::Log *log) const;
+ Dump (Log *log) const;
bool
DidDumpToLog () const
@@ -257,33 +291,59 @@ protected:
size_t payload_length);
PacketResult
+ ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout);
+
+ // Pop a packet from the queue in a thread safe manner
+ PacketResult
+ PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec);
+
+ PacketResult
WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response,
- uint32_t timeout_usec);
+ uint32_t timeout_usec,
+ bool sync_on_timeout);
+
+ bool
+ WaitForNotRunningPrivate (const TimeValue *timeout_ptr);
+
+ bool
+ CompressionIsEnabled ()
+ {
+ return m_compression_type != CompressionType::None;
+ }
+ // If compression is enabled, decompress the packet in m_bytes and update
+ // m_bytes with the uncompressed version.
+ // Returns 'true' packet was decompressed and m_bytes is the now-decompressed text.
+ // Returns 'false' if unable to decompress or if the checksum was invalid.
+ //
+ // NB: Once the packet has been decompressed, checksum cannot be computed based
+ // on m_bytes. The checksum was for the compressed packet.
bool
- WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr);
+ DecompressPacket ();
//------------------------------------------------------------------
// Classes that inherit from GDBRemoteCommunication can see and modify these
//------------------------------------------------------------------
uint32_t m_packet_timeout;
+ uint32_t m_echo_number;
+ LazyBool m_supports_qEcho;
#ifdef ENABLE_MUTEX_ERROR_CHECKING
- lldb_private::TrackingMutex m_sequence_mutex;
+ TrackingMutex m_sequence_mutex;
#else
- lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time
+ Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time
#endif
- lldb_private::Predicate<bool> m_public_is_running;
- lldb_private::Predicate<bool> m_private_is_running;
+ Predicate<bool> m_public_is_running;
+ Predicate<bool> m_private_is_running;
History m_history;
bool m_send_acks;
bool m_is_platform; // Set to true if this class represents a platform,
// false if this class represents a debug session for
// a single process
+ CompressionType m_compression_type;
- lldb_private::Error
- StartListenThread (const char *hostname = "127.0.0.1",
- uint16_t port = 0);
+ Error
+ StartListenThread (const char *hostname = "127.0.0.1", uint16_t port = 0);
bool
JoinListenThread ();
@@ -291,8 +351,25 @@ protected:
static lldb::thread_result_t
ListenThread (lldb::thread_arg_t arg);
+ // GDB-Remote read thread
+ // . this thread constantly tries to read from the communication
+ // class and stores all packets received in a queue. The usual
+ // threads read requests simply pop packets off the queue in the
+ // usual order.
+ // This setup allows us to intercept and handle async packets, such
+ // as the notify packet.
+
+ // This method is defined as part of communication.h
+ // when the read thread gets any bytes it will pass them on to this function
+ virtual void AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, lldb::ConnectionStatus status);
+
private:
- lldb_private::HostThread m_listen_thread;
+
+ std::queue<StringExtractorGDBRemote> m_packet_queue; // The packet queue
+ lldb_private::Mutex m_packet_queue_mutex; // Mutex for accessing queue
+ Condition m_condition_queue_not_empty; // Condition variable to wait for packets
+
+ HostThread m_listen_thread;
std::string m_listen_url;
//------------------------------------------------------------------
@@ -301,4 +378,7 @@ private:
DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication);
};
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
#endif // liblldb_GDBRemoteCommunication_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 0f99688fc823..ae0a2f5e66c5 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -11,16 +11,19 @@
#include "GDBRemoteCommunicationClient.h"
// C Includes
+#include <math.h>
#include <sys/stat.h>
// C++ Includes
#include <sstream>
+#include <numeric>
// Other libraries and framework includes
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamGDBRemote.h"
#include "lldb/Core/StreamString.h"
@@ -30,7 +33,10 @@
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Host/TimeValue.h"
+#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/Target.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/UnixSignals.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
@@ -38,18 +44,19 @@
#include "ProcessGDBRemoteLog.h"
#include "lldb/Host/Config.h"
+#if defined (HAVE_LIBCOMPRESSION)
+#include <compression.h>
+#endif
+
using namespace lldb;
using namespace lldb_private;
-
-#if defined(LLDB_DISABLE_POSIX) && !defined(SIGSTOP)
-#define SIGSTOP 17
-#endif
+using namespace lldb_private::process_gdb_remote;
//----------------------------------------------------------------------
// GDBRemoteCommunicationClient constructor
//----------------------------------------------------------------------
-GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
- GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet", is_platform),
+GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() :
+ GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet"),
m_supports_not_sending_acks (eLazyBoolCalculate),
m_supports_thread_suffix (eLazyBoolCalculate),
m_supports_threads_in_stop_reply (eLazyBoolCalculate),
@@ -77,6 +84,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_supports_qXfer_auxv_read (eLazyBoolCalculate),
m_supports_qXfer_libraries_read (eLazyBoolCalculate),
m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate),
+ m_supports_qXfer_features_read (eLazyBoolCalculate),
m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate),
m_supports_jThreadExtendedInfo (eLazyBoolCalculate),
m_supports_qProcessInfoPID (true),
@@ -91,6 +99,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_supports_z4 (true),
m_supports_QEnvironment (true),
m_supports_QEnvironmentHexEncoded (true),
+ m_supports_qSymbol (true),
+ m_supports_jThreadsInfo (true),
m_curr_pid (LLDB_INVALID_PROCESS_ID),
m_curr_tid (LLDB_INVALID_THREAD_ID),
m_curr_tid_run (LLDB_INVALID_THREAD_ID),
@@ -130,7 +140,7 @@ GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient()
bool
GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)
{
- ResetDiscoverableSettings();
+ ResetDiscoverableSettings(false);
// Start the read thread after we send the handshake ack since if we
// fail to send the handshake ack, there is no reason to continue...
@@ -142,7 +152,7 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)
PacketResult packet_result = PacketResult::Success;
const uint32_t timeout_usec = 10 * 1000; // Wait for 10 ms for a response
while (packet_result == PacketResult::Success)
- packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec);
+ packet_result = ReadPacket (response, timeout_usec, false);
// The return value from QueryNoAckModeSupported() is true if the packet
// was sent and _any_ response (including UNIMPLEMENTED) was received),
@@ -150,11 +160,6 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)
// a live connection to a remote GDB server...
if (QueryNoAckModeSupported())
{
-#if 0
- // Set above line to "#if 1" to test packet speed if remote GDB server
- // supports the qSpeedTest packet...
- TestPacketSpeed(10000);
-#endif
return true;
}
else
@@ -172,13 +177,24 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)
}
bool
+GDBRemoteCommunicationClient::GetEchoSupported ()
+{
+ if (m_supports_qEcho == eLazyBoolCalculate)
+ {
+ GetRemoteQSupported();
+ }
+ return m_supports_qEcho == eLazyBoolYes;
+}
+
+
+bool
GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported ()
{
if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate)
{
GetRemoteQSupported();
}
- return (m_supports_augmented_libraries_svr4_read == eLazyBoolYes);
+ return m_supports_augmented_libraries_svr4_read == eLazyBoolYes;
}
bool
@@ -188,7 +204,7 @@ GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported ()
{
GetRemoteQSupported();
}
- return (m_supports_qXfer_libraries_svr4_read == eLazyBoolYes);
+ return m_supports_qXfer_libraries_svr4_read == eLazyBoolYes;
}
bool
@@ -198,7 +214,7 @@ GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported ()
{
GetRemoteQSupported();
}
- return (m_supports_qXfer_libraries_read == eLazyBoolYes);
+ return m_supports_qXfer_libraries_read == eLazyBoolYes;
}
bool
@@ -208,7 +224,17 @@ GDBRemoteCommunicationClient::GetQXferAuxvReadSupported ()
{
GetRemoteQSupported();
}
- return (m_supports_qXfer_auxv_read == eLazyBoolYes);
+ return m_supports_qXfer_auxv_read == eLazyBoolYes;
+}
+
+bool
+GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported ()
+{
+ if (m_supports_qXfer_features_read == eLazyBoolCalculate)
+ {
+ GetRemoteQSupported();
+ }
+ return m_supports_qXfer_features_read == eLazyBoolYes;
}
uint64_t
@@ -234,13 +260,10 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported ()
const uint32_t minimum_timeout = 6;
uint32_t old_timeout = GetPacketTimeoutInMicroSeconds() / lldb_private::TimeValue::MicroSecPerSec;
- SetPacketTimeout (std::max (old_timeout, minimum_timeout));
+ GDBRemoteCommunication::ScopedTimeout timeout (*this, std::max (old_timeout, minimum_timeout));
StringExtractorGDBRemote response;
- PacketResult packet_send_result = SendPacketAndWaitForResponse("QStartNoAckMode", response, false);
- SetPacketTimeout (old_timeout);
-
- if (packet_send_result == PacketResult::Success)
+ if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success)
{
if (response.IsOKResponse())
{
@@ -311,58 +334,64 @@ GDBRemoteCommunicationClient::GetSyncThreadStateSupported ()
void
-GDBRemoteCommunicationClient::ResetDiscoverableSettings()
-{
- m_supports_not_sending_acks = eLazyBoolCalculate;
- m_supports_thread_suffix = eLazyBoolCalculate;
- m_supports_threads_in_stop_reply = eLazyBoolCalculate;
- m_supports_vCont_c = eLazyBoolCalculate;
- m_supports_vCont_C = eLazyBoolCalculate;
- 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;
+GDBRemoteCommunicationClient::ResetDiscoverableSettings (bool did_exec)
+{
+ if (did_exec == false)
+ {
+ // Hard reset everything, this is when we first connect to a GDB server
+ m_supports_not_sending_acks = eLazyBoolCalculate;
+ m_supports_thread_suffix = eLazyBoolCalculate;
+ m_supports_threads_in_stop_reply = eLazyBoolCalculate;
+ m_supports_vCont_c = eLazyBoolCalculate;
+ m_supports_vCont_C = eLazyBoolCalculate;
+ 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_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_qXfer_features_read = eLazyBoolCalculate;
+ m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;
+ m_supports_qProcessInfoPID = true;
+ m_supports_qfProcessInfo = true;
+ m_supports_qUserName = true;
+ m_supports_qGroupName = true;
+ m_supports_qThreadStopInfo = true;
+ m_supports_z0 = true;
+ m_supports_z1 = true;
+ m_supports_z2 = true;
+ m_supports_z3 = true;
+ m_supports_z4 = true;
+ m_supports_QEnvironment = true;
+ m_supports_QEnvironmentHexEncoded = true;
+ m_supports_qSymbol = true;
+ m_host_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;
+ }
+
+ // These flags should be reset when we first connect to a GDB server
+ // and when our inferior process execs
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;
-
- m_supports_qProcessInfoPID = true;
- m_supports_qfProcessInfo = true;
- m_supports_qUserName = true;
- m_supports_qGroupName = true;
- m_supports_qThreadStopInfo = true;
- m_supports_z0 = true;
- m_supports_z1 = true;
- m_supports_z2 = true;
- m_supports_z3 = true;
- 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;
}
void
@@ -373,10 +402,21 @@ GDBRemoteCommunicationClient::GetRemoteQSupported ()
m_supports_qXfer_libraries_read = eLazyBoolNo;
m_supports_qXfer_libraries_svr4_read = eLazyBoolNo;
m_supports_augmented_libraries_svr4_read = eLazyBoolNo;
+ m_supports_qXfer_features_read = eLazyBoolNo;
m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if not, we assume no limit
+ // build the qSupported packet
+ std::vector<std::string> features = {"xmlRegisters=i386,arm,mips"};
+ StreamString packet;
+ packet.PutCString( "qSupported" );
+ for ( uint32_t i = 0; i < features.size( ); ++i )
+ {
+ packet.PutCString( i==0 ? ":" : ";");
+ packet.PutCString( features[i].c_str( ) );
+ }
+
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("qSupported",
+ if (SendPacketAndWaitForResponse(packet.GetData(),
response,
/*send_async=*/false) == PacketResult::Success)
{
@@ -392,6 +432,66 @@ GDBRemoteCommunicationClient::GetRemoteQSupported ()
}
if (::strstr (response_cstr, "qXfer:libraries:read+"))
m_supports_qXfer_libraries_read = eLazyBoolYes;
+ if (::strstr (response_cstr, "qXfer:features:read+"))
+ m_supports_qXfer_features_read = eLazyBoolYes;
+
+
+ // Look for a list of compressions in the features list e.g.
+ // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-deflate,lzma
+ const char *features_list = ::strstr (response_cstr, "qXfer:features:");
+ if (features_list)
+ {
+ const char *compressions = ::strstr (features_list, "SupportedCompressions=");
+ if (compressions)
+ {
+ std::vector<std::string> supported_compressions;
+ compressions += sizeof ("SupportedCompressions=") - 1;
+ const char *end_of_compressions = strchr (compressions, ';');
+ if (end_of_compressions == NULL)
+ {
+ end_of_compressions = strchr (compressions, '\0');
+ }
+ const char *current_compression = compressions;
+ while (current_compression < end_of_compressions)
+ {
+ const char *next_compression_name = strchr (current_compression, ',');
+ const char *end_of_this_word = next_compression_name;
+ if (next_compression_name == NULL || end_of_compressions < next_compression_name)
+ {
+ end_of_this_word = end_of_compressions;
+ }
+
+ if (end_of_this_word)
+ {
+ if (end_of_this_word == current_compression)
+ {
+ current_compression++;
+ }
+ else
+ {
+ std::string this_compression (current_compression, end_of_this_word - current_compression);
+ supported_compressions.push_back (this_compression);
+ current_compression = end_of_this_word + 1;
+ }
+ }
+ else
+ {
+ supported_compressions.push_back (current_compression);
+ current_compression = end_of_compressions;
+ }
+ }
+
+ if (supported_compressions.size() > 0)
+ {
+ MaybeEnableCompression (supported_compressions);
+ }
+ }
+ }
+
+ if (::strstr (response_cstr, "qEcho"))
+ m_supports_qEcho = eLazyBoolYes;
+ else
+ m_supports_qEcho = eLazyBoolNo;
const char *packet_size_str = ::strstr (response_cstr, "PacketSize=");
if (packet_size_str)
@@ -509,6 +609,32 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid)
return m_supports_p;
}
+StructuredData::ObjectSP
+GDBRemoteCommunicationClient::GetThreadsInfo()
+{
+ // Get information on all threads at one using the "jThreadsInfo" packet
+ StructuredData::ObjectSP object_sp;
+
+ if (m_supports_jThreadsInfo)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_jThreadExtendedInfo = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == PacketResult::Success)
+ {
+ if (response.IsUnsupportedResponse())
+ {
+ m_supports_jThreadsInfo = false;
+ }
+ else if (!response.Empty())
+ {
+ object_sp = StructuredData::ParseJSON (response.GetStringRef());
+ }
+ }
+ }
+ return object_sp;
+}
+
+
bool
GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported ()
{
@@ -619,7 +745,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponseNoLock (const char *pa
{
PacketResult packet_result = SendPacketNoLock (payload, payload_length);
if (packet_result == PacketResult::Success)
- packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ());
+ packet_result = ReadPacket (response, GetPacketTimeoutInMicroSeconds (), true);
return packet_result;
}
@@ -635,6 +761,12 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
PacketResult packet_result = PacketResult::ErrorSendFailed;
Mutex::Locker locker;
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+
+ // In order to stop async notifications from being processed in the middle of the
+ // send/recieve sequence Hijack the broadcast. Then rebroadcast any events when we are done.
+ static Listener hijack_listener("lldb.NotifyHijacker");
+ HijackBroadcaster(&hijack_listener, eBroadcastBitGdbReadThreadGotNotify);
+
if (GetSequenceMutex (locker))
{
packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response);
@@ -726,6 +858,15 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload);
}
}
+
+ // Remove our Hijacking listner from the broadcast.
+ RestoreBroadcaster();
+
+ // If a notification event occured, rebroadcast since it can now be processed safely.
+ EventSP event_sp;
+ if (hijack_listener.GetNextEvent(event_sp))
+ BroadcastEvent(event_sp);
+
return packet_result;
}
@@ -822,6 +963,57 @@ GDBRemoteCommunicationClient::HarmonizeThreadIdsForProfileData
return final_output.str();
}
+bool
+GDBRemoteCommunicationClient::SendvContPacket
+(
+ ProcessGDBRemote *process,
+ const char *payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response
+)
+{
+
+ m_curr_tid = LLDB_INVALID_THREAD_ID;
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__);
+
+ // we want to lock down packet sending while we continue
+ Mutex::Locker locker(m_sequence_mutex);
+
+ // here we broadcast this before we even send the packet!!
+ // this signals doContinue() to exit
+ BroadcastEvent(eBroadcastBitRunPacketSent, NULL);
+
+ // set the public state to running
+ m_public_is_running.SetValue(true, eBroadcastNever);
+
+ // Set the starting continue packet into "continue_packet". This packet
+ // may change if we are interrupted and we continue after an async packet...
+ std::string continue_packet(payload, packet_length);
+
+ if (log)
+ log->Printf("GDBRemoteCommunicationClient::%s () sending vCont packet: %s", __FUNCTION__, continue_packet.c_str());
+
+ if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success)
+ return false;
+
+ // set the private state to running and broadcast this
+ m_private_is_running.SetValue(true, eBroadcastAlways);
+
+ if (log)
+ log->Printf("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str());
+
+ // wait for the response to the vCont
+ if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return true;
+ }
+
+ return false;
+}
+
StateType
GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse
(
@@ -844,7 +1036,10 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse
// Set the starting continue packet into "continue_packet". This packet
// may change if we are interrupted and we continue after an async packet...
std::string continue_packet(payload, packet_length);
-
+
+ const auto sigstop_signo = process->GetUnixSignals().GetSignalNumberFromName("SIGSTOP");
+ const auto sigint_signo = process->GetUnixSignals().GetSignalNumberFromName("SIGINT");
+
bool got_async_packet = false;
while (state == eStateRunning)
@@ -864,9 +1059,9 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse
got_async_packet = false;
if (log)
- log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(%s)", __FUNCTION__, continue_packet.c_str());
+ log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str());
- if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX) == PacketResult::Success)
+ if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success)
{
if (response.Empty())
state = eStateInvalid;
@@ -914,16 +1109,16 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse
// packet. If we don't do this, then the reply for our
// async packet will be the repeat stop reply packet and cause
// a lot of trouble for us!
- if (signo != SIGINT && signo != SIGSTOP)
+ if (signo != sigint_signo && signo != sigstop_signo)
{
continue_after_async = false;
- // We didn't get a a SIGINT or SIGSTOP, so try for a
+ // We didn't get a SIGINT or SIGSTOP, so try for a
// very brief time (1 ms) to get another stop reply
// packet to make sure it doesn't get in the way
StringExtractorGDBRemote extra_stop_reply_packet;
uint32_t timeout_usec = 1000;
- if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec) == PacketResult::Success)
+ if (ReadPacket (extra_stop_reply_packet, timeout_usec, false) == PacketResult::Success)
{
switch (extra_stop_reply_packet.GetChar())
{
@@ -1101,7 +1296,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse
else
{
if (log)
- log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(...) => false", __FUNCTION__);
+ log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(...) => false", __FUNCTION__);
state = eStateInvalid;
}
}
@@ -1287,7 +1482,7 @@ GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &laun
const char *arg = NULL;
const Args &launch_args = launch_info.GetArguments();
if (exe_file)
- exe_path = exe_file.GetPath();
+ exe_path = exe_file.GetPath(false);
else
{
arg = launch_args.GetArgumentAtIndex(0);
@@ -1576,6 +1771,105 @@ GDBRemoteCommunicationClient::GetGDBServerVersion()
return m_qGDBServerVersion_is_valid == eLazyBoolYes;
}
+void
+GDBRemoteCommunicationClient::MaybeEnableCompression (std::vector<std::string> supported_compressions)
+{
+ CompressionType avail_type = CompressionType::None;
+ std::string avail_name;
+
+#if defined (HAVE_LIBCOMPRESSION)
+ // libcompression is weak linked so test if compression_decode_buffer() is available
+ if (compression_decode_buffer != NULL && avail_type == CompressionType::None)
+ {
+ for (auto compression : supported_compressions)
+ {
+ if (compression == "lzfse")
+ {
+ avail_type = CompressionType::LZFSE;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined (HAVE_LIBCOMPRESSION)
+ // libcompression is weak linked so test if compression_decode_buffer() is available
+ if (compression_decode_buffer != NULL && avail_type == CompressionType::None)
+ {
+ for (auto compression : supported_compressions)
+ {
+ if (compression == "zlib-deflate")
+ {
+ avail_type = CompressionType::ZlibDeflate;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined (HAVE_LIBZ)
+ if (avail_type == CompressionType::None)
+ {
+ for (auto compression : supported_compressions)
+ {
+ if (compression == "zlib-deflate")
+ {
+ avail_type = CompressionType::ZlibDeflate;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined (HAVE_LIBCOMPRESSION)
+ // libcompression is weak linked so test if compression_decode_buffer() is available
+ if (compression_decode_buffer != NULL && avail_type == CompressionType::None)
+ {
+ for (auto compression : supported_compressions)
+ {
+ if (compression == "lz4")
+ {
+ avail_type = CompressionType::LZ4;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined (HAVE_LIBCOMPRESSION)
+ // libcompression is weak linked so test if compression_decode_buffer() is available
+ if (compression_decode_buffer != NULL && avail_type == CompressionType::None)
+ {
+ for (auto compression : supported_compressions)
+ {
+ if (compression == "lzma")
+ {
+ avail_type = CompressionType::LZMA;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+ if (avail_type != CompressionType::None)
+ {
+ StringExtractorGDBRemote response;
+ std::string packet = "QEnableCompression:type:" + avail_name + ";";
+ if (SendPacketAndWaitForResponse (packet.c_str(), response, false) != PacketResult::Success)
+ return;
+
+ if (response.IsOKResponse())
+ {
+ m_compression_type = avail_type;
+ }
+ }
+}
+
const char *
GDBRemoteCommunicationClient::GetGDBServerProgramName()
{
@@ -1596,6 +1890,22 @@ GDBRemoteCommunicationClient::GetGDBServerProgramVersion()
}
bool
+GDBRemoteCommunicationClient::GetDefaultThreadId (lldb::tid_t &tid)
+{
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qC",response,false) != PacketResult::Success)
+ return false;
+
+ if (!response.IsNormalResponse())
+ return false;
+
+ if (response.GetChar() == 'Q' && response.GetChar() == 'C')
+ tid = response.GetHexMaxU32(true, -1);
+
+ return true;
+}
+
+bool
GDBRemoteCommunicationClient::GetHostInfo (bool force)
{
Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS));
@@ -2167,13 +2477,14 @@ GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction (bool &after
}
int
-GDBRemoteCommunicationClient::SetSTDIN (char const *path)
+GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec)
{
- if (path && path[0])
+ if (file_spec)
{
+ std::string path{file_spec.GetPath(false)};
StreamString packet;
packet.PutCString("QSetSTDIN:");
- packet.PutBytesAsRawHex8(path, strlen(path));
+ packet.PutCStringAsRawHex8(path.c_str());
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
@@ -2189,14 +2500,15 @@ GDBRemoteCommunicationClient::SetSTDIN (char const *path)
}
int
-GDBRemoteCommunicationClient::SetSTDOUT (char const *path)
+GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec)
{
- if (path && path[0])
+ if (file_spec)
{
+ std::string path{file_spec.GetPath(false)};
StreamString packet;
packet.PutCString("QSetSTDOUT:");
- packet.PutBytesAsRawHex8(path, strlen(path));
-
+ packet.PutCStringAsRawHex8(path.c_str());
+
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
{
@@ -2211,14 +2523,15 @@ GDBRemoteCommunicationClient::SetSTDOUT (char const *path)
}
int
-GDBRemoteCommunicationClient::SetSTDERR (char const *path)
+GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec)
{
- if (path && path[0])
+ if (file_spec)
{
+ std::string path{file_spec.GetPath(false)};
StreamString packet;
packet.PutCString("QSetSTDERR:");
- packet.PutBytesAsRawHex8(path, strlen(path));
-
+ packet.PutCStringAsRawHex8(path.c_str());
+
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
{
@@ -2233,7 +2546,7 @@ GDBRemoteCommunicationClient::SetSTDERR (char const *path)
}
bool
-GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd)
+GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir)
{
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success)
@@ -2242,21 +2555,24 @@ GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd)
return false;
if (response.IsErrorResponse())
return false;
- response.GetHexByteString (cwd);
+ std::string cwd;
+ response.GetHexByteString(cwd);
+ working_dir.SetFile(cwd, false, GetHostArchitecture());
return !cwd.empty();
}
return false;
}
int
-GDBRemoteCommunicationClient::SetWorkingDir (char const *path)
+GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir)
{
- if (path && path[0])
+ if (working_dir)
{
+ std::string path{working_dir.GetPath(false)};
StreamString packet;
packet.PutCString("QSetWorkingDir:");
- packet.PutBytesAsRawHex8(path, strlen(path));
-
+ packet.PutCStringAsRawHex8(path.c_str());
+
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
{
@@ -2653,6 +2969,9 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat
}
}
StringExtractorGDBRemote response;
+ // Increase timeout as the first qfProcessInfo packet takes a long time
+ // on Android. The value of 1min was arrived at empirically.
+ GDBRemoteCommunication::ScopedTimeout timeout (*this, 60);
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
{
do
@@ -2734,87 +3053,184 @@ GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name)
return false;
}
+bool
+GDBRemoteCommunicationClient::SetNonStopMode (const bool enable)
+{
+ // Form non-stop packet request
+ char packet[32];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable);
+ assert(packet_len < (int)sizeof(packet));
+
+ StringExtractorGDBRemote response;
+ // Send to target
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ if (response.IsOKResponse())
+ return true;
+
+ // Failed or not supported
+ return false;
+
+}
+
+static void
+MakeSpeedTestPacket(StreamString &packet, uint32_t send_size, uint32_t recv_size)
+{
+ packet.Clear();
+ packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size);
+ uint32_t bytes_left = send_size;
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 26)
+ {
+ packet.PutCString("abcdefghijklmnopqrstuvwxyz");
+ bytes_left -= 26;
+ }
+ else
+ {
+ packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz");
+ bytes_left = 0;
+ }
+ }
+}
+
+template<typename T>
+T calculate_standard_deviation(const std::vector<T> &v)
+{
+ T sum = std::accumulate(std::begin(v), std::end(v), T(0));
+ T mean = sum / (T)v.size();
+ T accum = T(0);
+ std::for_each (std::begin(v), std::end(v), [&](const T d) {
+ T delta = d - mean;
+ accum += delta * delta;
+ });
+
+ T stdev = sqrt(accum / (v.size()-1));
+ return stdev;
+}
+
void
-GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets)
+GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm)
{
uint32_t i;
TimeValue start_time, end_time;
uint64_t total_time_nsec;
if (SendSpeedTestPacket (0, 0))
{
- 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 = 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)
- {
- const uint32_t send_size = g_send_sizes[send_idx];
- for (uint32_t recv_idx = 0; recv_idx < k_num_recv_sizes; ++recv_idx)
- {
- const uint32_t recv_size = g_recv_sizes[recv_idx];
- StreamString packet;
- packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size);
- uint32_t bytes_left = send_size;
- while (bytes_left > 0)
+ StreamString packet;
+ if (json)
+ strm.Printf("{ \"packet_speeds\" : {\n \"num_packets\" : %u,\n \"results\" : [", num_packets);
+ else
+ strm.Printf("Testing sending %u packets of various sizes:\n", num_packets);
+ strm.Flush();
+
+ uint32_t result_idx = 0;
+ uint32_t send_size;
+ std::vector<float> packet_times;
+
+ for (send_size = 0; send_size <= max_send; send_size ? send_size *= 2 : send_size = 4)
+ {
+ for (uint32_t recv_size = 0; recv_size <= max_recv; recv_size ? recv_size *= 2 : recv_size = 4)
+ {
+ MakeSpeedTestPacket (packet, send_size, recv_size);
+
+ packet_times.clear();
+ // Test how long it takes to send 'num_packets' packets
+ start_time = TimeValue::Now();
+ for (i=0; i<num_packets; ++i)
{
- if (bytes_left >= 26)
- {
- packet.PutCString("abcdefghijklmnopqrstuvwxyz");
- bytes_left -= 26;
- }
- else
- {
- packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz");
- bytes_left = 0;
- }
+ TimeValue packet_start_time = TimeValue::Now();
+ StringExtractorGDBRemote response;
+ SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false);
+ TimeValue packet_end_time = TimeValue::Now();
+ uint64_t packet_time_nsec = packet_end_time.GetAsNanoSecondsSinceJan1_1970() - packet_start_time.GetAsNanoSecondsSinceJan1_1970();
+ packet_times.push_back((float)packet_time_nsec);
}
+ end_time = TimeValue::Now();
+ total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970();
- start_time = TimeValue::Now();
- if (recv_size == 0)
+ float packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec;
+ float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec;
+ float average_ms_per_packet = total_ms / num_packets;
+ const float standard_deviation = calculate_standard_deviation<float>(packet_times);
+ if (json)
{
- for (i=0; i<num_packets; ++i)
- {
- StringExtractorGDBRemote response;
- SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false);
- }
+ strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 ", \"standard_deviation_nsec\" : %9" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec, (uint64_t)standard_deviation);
+ ++result_idx;
}
else
{
- uint32_t bytes_read = 0;
- while (bytes_read < k_recv_amount)
- {
- StringExtractorGDBRemote response;
- SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false);
- bytes_read += recv_size;
- }
+ strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) in %" PRIu64 ".%9.9" PRIu64 " sec for %9.2f packets/sec (%10.6f ms per packet) with standard deviation of %10.6f ms\n",
+ send_size,
+ recv_size,
+ total_time_nsec / TimeValue::NanoSecPerSec,
+ total_time_nsec % TimeValue::NanoSecPerSec,
+ packets_per_second,
+ average_ms_per_packet,
+ standard_deviation/(float)TimeValue::NanoSecPerMilliSec);
+ }
+ strm.Flush();
+ }
+ }
+
+ const uint64_t k_recv_amount = 4*1024*1024; // Receive amount in bytes
+
+ const float k_recv_amount_mb = (float)k_recv_amount/(1024.0f*1024.0f);
+ if (json)
+ strm.Printf("\n ]\n },\n \"download_speed\" : {\n \"byte_size\" : %" PRIu64 ",\n \"results\" : [", k_recv_amount);
+ else
+ strm.Printf("Testing receiving %2.1fMB of data using varying receive packet sizes:\n", k_recv_amount_mb);
+ strm.Flush();
+ send_size = 0;
+ result_idx = 0;
+ for (uint32_t recv_size = 32; recv_size <= max_recv; recv_size *= 2)
+ {
+ MakeSpeedTestPacket (packet, send_size, recv_size);
+
+ // If we have a receive size, test how long it takes to receive 4MB of data
+ if (recv_size > 0)
+ {
+ start_time = TimeValue::Now();
+ uint32_t bytes_read = 0;
+ uint32_t packet_count = 0;
+ while (bytes_read < k_recv_amount)
+ {
+ StringExtractorGDBRemote response;
+ SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false);
+ bytes_read += recv_size;
+ ++packet_count;
}
end_time = TimeValue::Now();
total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970();
- if (recv_size == 0)
+ float mb_second = ((((float)k_recv_amount)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec) / (1024.0*1024.0);
+ float packets_per_second = (((float)packet_count)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec;
+ float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec;
+ float average_ms_per_packet = total_ms / packet_count;
+
+ if (json)
{
- float packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec;
- printf ("%u qSpeedTest(send=%-7u, recv=%-7u) in %" PRIu64 ".%9.9" PRIu64 " sec for %f packets/sec.\n",
- num_packets,
- send_size,
- recv_size,
- total_time_nsec / TimeValue::NanoSecPerSec,
- total_time_nsec % TimeValue::NanoSecPerSec,
- packets_per_second);
+ strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec);
+ ++result_idx;
}
else
{
- float mb_second = ((((float)k_recv_amount)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec) / (1024.0*1024.0);
- printf ("%u qSpeedTest(send=%-7u, recv=%-7u) sent 4MB in %" PRIu64 ".%9.9" PRIu64 " sec for %f MB/sec.\n",
- num_packets,
- send_size,
- recv_size,
- total_time_nsec / TimeValue::NanoSecPerSec,
- total_time_nsec % TimeValue::NanoSecPerSec,
- mb_second);
+ strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) %6u packets needed to receive %2.1fMB in %" PRIu64 ".%9.9" PRIu64 " sec for %f MB/sec for %9.2f packets/sec (%10.6f ms per packet)\n",
+ send_size,
+ recv_size,
+ packet_count,
+ k_recv_amount_mb,
+ total_time_nsec / TimeValue::NanoSecPerSec,
+ total_time_nsec % TimeValue::NanoSecPerSec,
+ mb_second,
+ packets_per_second,
+ average_ms_per_packet);
}
+ strm.Flush();
}
}
+ if (json)
+ strm.Printf("\n ]\n }\n}\n");
+ else
+ strm.EOL();
}
}
@@ -2869,10 +3285,9 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const
int packet_len = stream.GetSize();
// give the process a few seconds to startup
- const uint32_t old_packet_timeout = SetPacketTimeout (10);
- auto result = SendPacketAndWaitForResponse(packet, packet_len, response, false);
- SetPacketTimeout (old_packet_timeout);
- if (result == PacketResult::Success)
+ GDBRemoteCommunication::ScopedTimeout timeout (*this, 10);
+
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
{
std::string name;
std::string value;
@@ -3109,22 +3524,23 @@ GDBRemoteCommunicationClient::GetShlibInfoAddr()
}
lldb_private::Error
-GDBRemoteCommunicationClient::RunShellCommand (const char *command, // Shouldn't be NULL
- const char *working_dir, // Pass NULL to use the current working directory
- int *status_ptr, // Pass NULL if you don't want the process exit status
- int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
- std::string *command_output, // Pass NULL if you don't want the command output
- uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
+GDBRemoteCommunicationClient::RunShellCommand(const char *command, // Shouldn't be NULL
+ const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
{
lldb_private::StreamString stream;
stream.PutCString("qPlatform_shell:");
stream.PutBytesAsRawHex8(command, strlen(command));
stream.PutChar(',');
stream.PutHex32(timeout_sec);
- if (working_dir && *working_dir)
+ if (working_dir)
{
+ std::string path{working_dir.GetPath(false)};
stream.PutChar(',');
- stream.PutBytesAsRawHex8(working_dir, strlen(working_dir));
+ stream.PutCStringAsRawHex8(path.c_str());
}
const char *packet = stream.GetData();
int packet_len = stream.GetSize();
@@ -3157,43 +3573,49 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, //
}
Error
-GDBRemoteCommunicationClient::MakeDirectory (const char *path,
- uint32_t file_permissions)
+GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec,
+ uint32_t file_permissions)
{
+ std::string path{file_spec.GetPath(false)};
lldb_private::StreamString stream;
stream.PutCString("qPlatform_mkdir:");
stream.PutHex32(file_permissions);
stream.PutChar(',');
- stream.PutBytesAsRawHex8(path, strlen(path));
+ stream.PutCStringAsRawHex8(path.c_str());
const char *packet = stream.GetData();
int packet_len = stream.GetSize();
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
- {
- return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX);
- }
- return Error();
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success)
+ return Error("failed to send '%s' packet", packet);
+
+ if (response.GetChar() != 'F')
+ return Error("invalid response to '%s' packet", packet);
+
+ return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX);
}
Error
-GDBRemoteCommunicationClient::SetFilePermissions (const char *path,
- uint32_t file_permissions)
+GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions)
{
+ std::string path{file_spec.GetPath(false)};
lldb_private::StreamString stream;
stream.PutCString("qPlatform_chmod:");
stream.PutHex32(file_permissions);
stream.PutChar(',');
- stream.PutBytesAsRawHex8(path, strlen(path));
+ stream.PutCStringAsRawHex8(path.c_str());
const char *packet = stream.GetData();
int packet_len = stream.GetSize();
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
- {
- return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX);
- }
- return Error();
-
+
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success)
+ return Error("failed to send '%s' packet", packet);
+
+ if (response.GetChar() != 'F')
+ return Error("invalid response to '%s' packet", packet);
+
+ return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX);
}
static uint64_t
@@ -3225,15 +3647,14 @@ GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec,
mode_t mode,
Error &error)
{
+ std::string path(file_spec.GetPath(false));
lldb_private::StreamString stream;
stream.PutCString("vFile:open:");
- std::string path (file_spec.GetPath());
if (path.empty())
return UINT64_MAX;
stream.PutCStringAsRawHex8(path.c_str());
stream.PutChar(',');
- const uint32_t posix_open_flags = File::ConvertOpenOptionsForPOSIXOpen(flags);
- stream.PutHex32(posix_open_flags);
+ stream.PutHex32(flags);
stream.PutChar(',');
stream.PutHex32(mode);
const char* packet = stream.GetData();
@@ -3266,9 +3687,9 @@ GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd,
lldb::user_id_t
GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec)
{
+ std::string path(file_spec.GetPath(false));
lldb_private::StreamString stream;
stream.PutCString("vFile:size:");
- std::string path (file_spec.GetPath());
stream.PutCStringAsRawHex8(path.c_str());
const char* packet = stream.GetData();
int packet_len = stream.GetSize();
@@ -3284,12 +3705,14 @@ GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_sp
}
Error
-GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &file_permissions)
+GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions)
{
+ std::string path{file_spec.GetPath(false)};
Error error;
lldb_private::StreamString stream;
stream.PutCString("vFile:mode:");
- stream.PutCStringAsRawHex8(path);
+ stream.PutCStringAsRawHex8(path.c_str());
const char* packet = stream.GetData();
int packet_len = stream.GetSize();
StringExtractorGDBRemote response;
@@ -3408,16 +3831,18 @@ GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd,
}
Error
-GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst)
+GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, const FileSpec &dst)
{
+ std::string src_path{src.GetPath(false)},
+ dst_path{dst.GetPath(false)};
Error error;
lldb_private::StreamGDBRemote stream;
stream.PutCString("vFile:symlink:");
// the unix symlink() command reverses its parameters where the dst if first,
// so we follow suit here
- stream.PutCStringAsRawHex8(dst);
+ stream.PutCStringAsRawHex8(dst_path.c_str());
stream.PutChar(',');
- stream.PutCStringAsRawHex8(src);
+ stream.PutCStringAsRawHex8(src_path.c_str());
const char* packet = stream.GetData();
int packet_len = stream.GetSize();
StringExtractorGDBRemote response;
@@ -3451,14 +3876,15 @@ GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst)
}
Error
-GDBRemoteCommunicationClient::Unlink (const char *path)
+GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec)
{
+ std::string path{file_spec.GetPath(false)};
Error error;
lldb_private::StreamGDBRemote stream;
stream.PutCString("vFile:unlink:");
// the unix symlink() command reverses its parameters where the dst if first,
// so we follow suit here
- stream.PutCStringAsRawHex8(path);
+ stream.PutCStringAsRawHex8(path.c_str());
const char* packet = stream.GetData();
int packet_len = stream.GetSize();
StringExtractorGDBRemote response;
@@ -3495,9 +3921,9 @@ GDBRemoteCommunicationClient::Unlink (const char *path)
bool
GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec)
{
+ std::string path(file_spec.GetPath(false));
lldb_private::StreamString stream;
stream.PutCString("vFile:exists:");
- std::string path (file_spec.GetPath());
stream.PutCStringAsRawHex8(path.c_str());
const char* packet = stream.GetData();
int packet_len = stream.GetSize();
@@ -3519,9 +3945,9 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s
uint64_t &high,
uint64_t &low)
{
+ std::string path(file_spec.GetPath(false));
lldb_private::StreamString stream;
stream.PutCString("vFile:MD5:");
- std::string path (file_spec.GetPath());
stream.PutCStringAsRawHex8(path.c_str());
const char* packet = stream.GetData();
int packet_len = stream.GetSize();
@@ -3639,7 +4065,7 @@ GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save
if (thread_suffix_supported)
::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid);
else
- ::strncpy (packet, "QSaveRegisterState", sizeof(packet));
+ ::snprintf(packet, sizeof(packet), "QSaveRegisterState");
StringExtractorGDBRemote response;
@@ -3703,3 +4129,274 @@ GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t sa
}
return false;
}
+
+bool
+GDBRemoteCommunicationClient::GetModuleInfo (const FileSpec& module_file_spec,
+ const lldb_private::ArchSpec& arch_spec,
+ ModuleSpec &module_spec)
+{
+ std::string module_path = module_file_spec.GetPath (false);
+ if (module_path.empty ())
+ return false;
+
+ StreamString packet;
+ packet.PutCString("qModuleInfo:");
+ packet.PutCStringAsRawHex8(module_path.c_str());
+ packet.PutCString(";");
+ const auto& triple = arch_spec.GetTriple().getTriple();
+ packet.PutCStringAsRawHex8(triple.c_str());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) != PacketResult::Success)
+ return false;
+
+ if (response.IsErrorResponse () || response.IsUnsupportedResponse ())
+ return false;
+
+ std::string name;
+ std::string value;
+ bool success;
+ StringExtractor extractor;
+
+ module_spec.Clear ();
+ module_spec.GetFileSpec () = module_file_spec;
+
+ while (response.GetNameColonValue (name, value))
+ {
+ if (name == "uuid" || name == "md5")
+ {
+ extractor.GetStringRef ().swap (value);
+ extractor.SetFilePos (0);
+ extractor.GetHexByteString (value);
+ module_spec.GetUUID().SetFromCString (value.c_str(), value.size() / 2);
+ }
+ else if (name == "triple")
+ {
+ extractor.GetStringRef ().swap (value);
+ extractor.SetFilePos (0);
+ extractor.GetHexByteString (value);
+ module_spec.GetArchitecture().SetTriple (value.c_str ());
+ }
+ else if (name == "file_offset")
+ {
+ const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success);
+ if (success)
+ module_spec.SetObjectOffset (ival);
+ }
+ else if (name == "file_size")
+ {
+ const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success);
+ if (success)
+ module_spec.SetObjectSize (ival);
+ }
+ else if (name == "file_path")
+ {
+ extractor.GetStringRef ().swap (value);
+ extractor.SetFilePos (0);
+ extractor.GetHexByteString (value);
+ module_spec.GetFileSpec() = FileSpec(value.c_str(), false, arch_spec);
+ }
+ }
+
+ return true;
+}
+
+// query the target remote for extended information using the qXfer packet
+//
+// example: object='features', annex='target.xml', out=<xml output>
+// return: 'true' on success
+// 'false' on failure (err set)
+bool
+GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString object,
+ const lldb_private::ConstString annex,
+ std::string & out,
+ lldb_private::Error & err) {
+
+ std::stringstream output;
+ StringExtractorGDBRemote chunk;
+
+ uint64_t size = GetRemoteMaxPacketSize();
+ if (size == 0)
+ size = 0x1000;
+ size = size - 1; // Leave space for the 'm' or 'l' character in the response
+ int offset = 0;
+ bool active = true;
+
+ // loop until all data has been read
+ while ( active ) {
+
+ // send query extended feature packet
+ std::stringstream packet;
+ packet << "qXfer:"
+ << object.AsCString("") << ":read:"
+ << annex.AsCString("") << ":"
+ << std::hex << offset << ","
+ << std::hex << size;
+
+ GDBRemoteCommunication::PacketResult res =
+ SendPacketAndWaitForResponse( packet.str().c_str(),
+ chunk,
+ false );
+
+ if ( res != GDBRemoteCommunication::PacketResult::Success ) {
+ err.SetErrorString( "Error sending $qXfer packet" );
+ return false;
+ }
+
+ const std::string & str = chunk.GetStringRef( );
+ if ( str.length() == 0 ) {
+ // should have some data in chunk
+ err.SetErrorString( "Empty response from $qXfer packet" );
+ return false;
+ }
+
+ // check packet code
+ switch ( str[0] ) {
+ // last chunk
+ case ( 'l' ):
+ active = false;
+ // fall through intentional
+
+ // more chunks
+ case ( 'm' ) :
+ if ( str.length() > 1 )
+ output << &str[1];
+ offset += size;
+ break;
+
+ // unknown chunk
+ default:
+ err.SetErrorString( "Invalid continuation code from $qXfer packet" );
+ return false;
+ }
+ }
+
+ out = output.str( );
+ err.Success( );
+ return true;
+}
+
+// Notify the target that gdb is prepared to serve symbol lookup requests.
+// packet: "qSymbol::"
+// reply:
+// OK The target does not need to look up any (more) symbols.
+// qSymbol:<sym_name> The target requests the value of symbol sym_name (hex encoded).
+// LLDB may provide the value by sending another qSymbol packet
+// in the form of"qSymbol:<sym_value>:<sym_name>".
+
+void
+GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process)
+{
+ if (m_supports_qSymbol)
+ {
+ Mutex::Locker locker;
+ if (GetSequenceMutex(locker, "GDBRemoteCommunicationClient::ServeSymbolLookups() failed due to not getting the sequence mutex"))
+ {
+ StreamString packet;
+ packet.PutCString ("qSymbol::");
+ while (1)
+ {
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponseNoLock(packet.GetData(), packet.GetSize(), response) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ // We are done serving symbols requests
+ return;
+ }
+
+ if (response.IsUnsupportedResponse())
+ {
+ // qSymbol is not supported by the current GDB server we are connected to
+ m_supports_qSymbol = false;
+ return;
+ }
+ else
+ {
+ llvm::StringRef response_str(response.GetStringRef());
+ if (response_str.startswith("qSymbol:"))
+ {
+ response.SetFilePos(strlen("qSymbol:"));
+ std::string symbol_name;
+ if (response.GetHexByteString(symbol_name))
+ {
+ if (symbol_name.empty())
+ return;
+
+ addr_t symbol_load_addr = LLDB_INVALID_ADDRESS;
+ lldb_private::SymbolContextList sc_list;
+ if (process->GetTarget().GetImages().FindSymbolsWithNameAndType(ConstString(symbol_name), eSymbolTypeAny, sc_list))
+ {
+ const size_t num_scs = sc_list.GetSize();
+ for (size_t sc_idx=0; sc_idx<num_scs && symbol_load_addr == LLDB_INVALID_ADDRESS; ++sc_idx)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(sc_idx, sc))
+ {
+ if (sc.symbol)
+ {
+ switch (sc.symbol->GetType())
+ {
+ case eSymbolTypeInvalid:
+ case eSymbolTypeAbsolute:
+ case eSymbolTypeUndefined:
+ case eSymbolTypeSourceFile:
+ case eSymbolTypeHeaderFile:
+ case eSymbolTypeObjectFile:
+ case eSymbolTypeCommonBlock:
+ case eSymbolTypeBlock:
+ case eSymbolTypeLocal:
+ case eSymbolTypeParam:
+ case eSymbolTypeVariable:
+ case eSymbolTypeVariableType:
+ case eSymbolTypeLineEntry:
+ case eSymbolTypeLineHeader:
+ case eSymbolTypeScopeBegin:
+ case eSymbolTypeScopeEnd:
+ case eSymbolTypeAdditional:
+ case eSymbolTypeCompiler:
+ case eSymbolTypeInstrumentation:
+ case eSymbolTypeTrampoline:
+ break;
+
+ case eSymbolTypeCode:
+ case eSymbolTypeResolver:
+ case eSymbolTypeData:
+ case eSymbolTypeRuntime:
+ case eSymbolTypeException:
+ case eSymbolTypeObjCClass:
+ case eSymbolTypeObjCMetaClass:
+ case eSymbolTypeObjCIVar:
+ case eSymbolTypeReExported:
+ symbol_load_addr = sc.symbol->GetLoadAddress(&process->GetTarget());
+ break;
+ }
+ }
+ }
+ }
+ }
+ // This is the normal path where our symbol lookup was successful and we want
+ // to send a packet with the new symbol value and see if another lookup needs to be
+ // done.
+
+ // Change "packet" to contain the requested symbol value and name
+ packet.Clear();
+ packet.PutCString("qSymbol:");
+ if (symbol_load_addr != LLDB_INVALID_ADDRESS)
+ packet.Printf("%" PRIx64, symbol_load_addr);
+ packet.PutCString(":");
+ packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size());
+ continue; // go back to the while loop and send "packet" and wait for another response
+ }
+ }
+ }
+ }
+ }
+ // If we make it here, the symbol request packet response wasn't valid or
+ // our symbol lookup failed so we must abort
+ return;
+
+ }
+ }
+}
+
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index d90614bce88b..65a2981018ea 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -17,17 +17,21 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Target/Process.h"
#include "GDBRemoteCommunication.h"
+namespace lldb_private {
+namespace process_gdb_remote {
+
class GDBRemoteCommunicationClient : public GDBRemoteCommunication
{
public:
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
- GDBRemoteCommunicationClient(bool is_platform);
+ GDBRemoteCommunicationClient();
~GDBRemoteCommunicationClient();
@@ -36,7 +40,7 @@ public:
// we are communicating with it.
//------------------------------------------------------------------
bool
- HandshakeWithServer (lldb_private::Error *error_ptr);
+ HandshakeWithServer (Error *error_ptr);
PacketResult
SendPacketAndWaitForResponse (const char *send_payload,
@@ -75,9 +79,14 @@ public:
const char *packet_payload,
size_t packet_length,
StringExtractorGDBRemote &response);
+ bool
+ SendvContPacket (ProcessGDBRemote *process,
+ const char *payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response);
bool
- GetThreadSuffixSupported ();
+ GetThreadSuffixSupported () override;
// This packet is usually sent first and the boolean return value
// indicates if the packet was send and any response was received
@@ -95,7 +104,7 @@ public:
SendAsyncSignal (int signo);
bool
- SendInterrupt (lldb_private::Mutex::Locker &locker,
+ SendInterrupt (Mutex::Locker &locker,
uint32_t seconds_to_wait_for_stop,
bool &timed_out);
@@ -126,7 +135,7 @@ public:
/// response was received.
//------------------------------------------------------------------
int
- SendArgumentsPacket (const lldb_private::ProcessLaunchInfo &launch_info);
+ SendArgumentsPacket (const ProcessLaunchInfo &launch_info);
//------------------------------------------------------------------
/// Sends a "QEnvironment:NAME=VALUE" packet that will build up the
@@ -202,11 +211,11 @@ public:
/// Zero if the for success, or an error code for failure.
//------------------------------------------------------------------
int
- SetSTDIN (char const *path);
+ SetSTDIN(const FileSpec &file_spec);
int
- SetSTDOUT (char const *path);
+ SetSTDOUT(const FileSpec &file_spec);
int
- SetSTDERR (char const *path);
+ SetSTDERR(const FileSpec &file_spec);
//------------------------------------------------------------------
/// Sets the disable ASLR flag to \a enable for a process that will
@@ -240,27 +249,27 @@ public:
/// implements the platform, it will change the current working
/// directory for the platform process.
///
- /// @param[in] path
+ /// @param[in] working_dir
/// The path to a directory to use when launching our process
///
/// @return
/// Zero if the for success, or an error code for failure.
//------------------------------------------------------------------
int
- SetWorkingDir (char const *path);
+ SetWorkingDir(const FileSpec &working_dir);
//------------------------------------------------------------------
/// Gets the current working directory of a remote platform GDB
/// server.
///
- /// @param[out] cwd
+ /// @param[out] working_dir
/// The current working directory on the remote platform.
///
/// @return
/// Boolean for success
//------------------------------------------------------------------
bool
- GetWorkingDir (std::string &cwd);
+ GetWorkingDir(FileSpec &working_dir);
lldb::addr_t
AllocateMemory (size_t size, uint32_t permissions);
@@ -268,29 +277,28 @@ public:
bool
DeallocateMemory (lldb::addr_t addr);
- lldb_private::Error
+ Error
Detach (bool keep_stopped);
- lldb_private::Error
- GetMemoryRegionInfo (lldb::addr_t addr,
- lldb_private::MemoryRegionInfo &range_info);
+ Error
+ GetMemoryRegionInfo (lldb::addr_t addr, MemoryRegionInfo &range_info);
- lldb_private::Error
+ Error
GetWatchpointSupportInfo (uint32_t &num);
- lldb_private::Error
+ Error
GetWatchpointSupportInfo (uint32_t &num, bool& after);
- lldb_private::Error
+ Error
GetWatchpointsTriggerAfterInstruction (bool &after);
- const lldb_private::ArchSpec &
+ const ArchSpec &
GetHostArchitecture ();
uint32_t
GetHostDefaultPacketTimeout();
- const lldb_private::ArchSpec &
+ const ArchSpec &
GetProcessArchitecture ();
void
@@ -312,10 +320,13 @@ public:
GetSyncThreadStateSupported();
void
- ResetDiscoverableSettings();
+ ResetDiscoverableSettings (bool did_exec);
bool
GetHostInfo (bool force = false);
+
+ bool
+ GetDefaultThreadId (lldb::tid_t &tid);
bool
GetOSVersion (uint32_t &major,
@@ -328,7 +339,7 @@ public:
bool
GetOSKernelDescription (std::string &s);
- lldb_private::ArchSpec
+ ArchSpec
GetSystemArchitecture ();
bool
@@ -341,12 +352,11 @@ public:
GetSupportsThreadSuffix ();
bool
- GetProcessInfo (lldb::pid_t pid,
- lldb_private::ProcessInstanceInfo &process_info);
+ GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info);
uint32_t
- FindProcesses (const lldb_private::ProcessInstanceInfoMatch &process_match_info,
- lldb_private::ProcessInstanceInfoList &process_infos);
+ FindProcesses (const ProcessInstanceInfoMatch &process_match_info,
+ ProcessInstanceInfoList &process_infos);
bool
GetUserName (uint32_t uid, std::string &name);
@@ -383,7 +393,7 @@ public:
case eWatchpointWrite: return m_supports_z2;
case eWatchpointRead: return m_supports_z3;
case eWatchpointReadWrite: return m_supports_z4;
- case eStoppointInvalid: return false;
+ default: return false;
}
}
uint8_t
@@ -392,8 +402,11 @@ public:
lldb::addr_t addr, // Address of breakpoint or watchpoint
uint32_t length); // Byte Size of breakpoint or watchpoint
+ bool
+ SetNonStopMode (const bool enable);
+
void
- TestPacketSpeed (const uint32_t num_packets);
+ TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm);
// This packet is for testing the speed of the interface only. Both
// the client and server need to support it, but this allows us to
@@ -423,9 +436,15 @@ public:
GetRemoteMaxPacketSize();
bool
+ GetEchoSupported ();
+
+ bool
GetAugmentedLibrariesSVR4ReadSupported ();
- lldb_private::LazyBool
+ bool
+ GetQXferFeaturesReadSupported ();
+
+ LazyBool
SupportsAllocDeallocMemory () // const
{
// Uncomment this to have lldb pretend the debug server doesn't respond to alloc/dealloc memory packets.
@@ -444,64 +463,57 @@ public:
}
lldb::user_id_t
- OpenFile (const lldb_private::FileSpec& file_spec,
- uint32_t flags,
- mode_t mode,
- lldb_private::Error &error);
+ OpenFile (const FileSpec& file_spec, uint32_t flags, mode_t mode, Error &error);
bool
- CloseFile (lldb::user_id_t fd,
- lldb_private::Error &error);
+ CloseFile (lldb::user_id_t fd, Error &error);
lldb::user_id_t
- GetFileSize (const lldb_private::FileSpec& file_spec);
+ GetFileSize (const FileSpec& file_spec);
- lldb_private::Error
- GetFilePermissions(const char *path, uint32_t &file_permissions);
+ Error
+ GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions);
- lldb_private::Error
- SetFilePermissions(const char *path, uint32_t file_permissions);
+ Error
+ SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions);
uint64_t
ReadFile (lldb::user_id_t fd,
uint64_t offset,
void *dst,
uint64_t dst_len,
- lldb_private::Error &error);
+ Error &error);
uint64_t
WriteFile (lldb::user_id_t fd,
uint64_t offset,
const void* src,
uint64_t src_len,
- lldb_private::Error &error);
+ Error &error);
- lldb_private::Error
- CreateSymlink (const char *src,
- const char *dst);
+ Error
+ CreateSymlink(const FileSpec &src,
+ const FileSpec &dst);
- lldb_private::Error
- Unlink (const char *path);
+ Error
+ Unlink(const FileSpec &file_spec);
+
+ Error
+ MakeDirectory(const FileSpec &file_spec, uint32_t mode);
- lldb_private::Error
- MakeDirectory (const char *path,
- uint32_t mode);
-
bool
- GetFileExists (const lldb_private::FileSpec& file_spec);
-
- lldb_private::Error
- RunShellCommand (const char *command, // Shouldn't be NULL
- const char *working_dir, // Pass NULL to use the current working directory
- int *status_ptr, // Pass NULL if you don't want the process exit status
- int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
- std::string *command_output, // Pass NULL if you don't want the command output
- uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish
+ GetFileExists (const FileSpec& file_spec);
+ Error
+ RunShellCommand(const char *command, // Shouldn't be NULL
+ const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish
+
bool
- CalculateMD5 (const lldb_private::FileSpec& file_spec,
- uint64_t &high,
- uint64_t &low);
+ CalculateMD5 (const FileSpec& file_spec, uint64_t &high, uint64_t &low);
std::string
HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process,
@@ -531,9 +543,26 @@ public:
bool
AvoidGPackets(ProcessGDBRemote *process);
+ StructuredData::ObjectSP
+ GetThreadsInfo();
+
bool
GetThreadExtendedInfoSupported();
+ bool
+ GetModuleInfo (const FileSpec& module_file_spec,
+ const ArchSpec& arch_spec,
+ ModuleSpec &module_spec);
+
+ bool
+ ReadExtFeature (const lldb_private::ConstString object,
+ const lldb_private::ConstString annex,
+ std::string & out,
+ lldb_private::Error & err);
+
+ void
+ ServeSymbolLookups(lldb_private::Process *process);
+
protected:
PacketResult
@@ -547,38 +576,44 @@ protected:
bool
GetGDBServerVersion();
+ // Given the list of compression types that the remote debug stub can support,
+ // possibly enable compression if we find an encoding we can handle.
+ void
+ MaybeEnableCompression (std::vector<std::string> supported_compressions);
+
//------------------------------------------------------------------
// Classes that inherit from GDBRemoteCommunicationClient can see and modify these
//------------------------------------------------------------------
- lldb_private::LazyBool m_supports_not_sending_acks;
- lldb_private::LazyBool m_supports_thread_suffix;
- lldb_private::LazyBool m_supports_threads_in_stop_reply;
- lldb_private::LazyBool m_supports_vCont_all;
- lldb_private::LazyBool m_supports_vCont_any;
- lldb_private::LazyBool m_supports_vCont_c;
- lldb_private::LazyBool m_supports_vCont_C;
- 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;
- lldb_private::LazyBool m_supports_detach_stay_stopped;
- lldb_private::LazyBool m_watchpoints_trigger_after_instruction;
- 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;
+ LazyBool m_supports_not_sending_acks;
+ LazyBool m_supports_thread_suffix;
+ LazyBool m_supports_threads_in_stop_reply;
+ LazyBool m_supports_vCont_all;
+ LazyBool m_supports_vCont_any;
+ LazyBool m_supports_vCont_c;
+ LazyBool m_supports_vCont_C;
+ LazyBool m_supports_vCont_s;
+ LazyBool m_supports_vCont_S;
+ LazyBool m_qHostInfo_is_valid;
+ LazyBool m_curr_pid_is_valid;
+ LazyBool m_qProcessInfo_is_valid;
+ LazyBool m_qGDBServerVersion_is_valid;
+ LazyBool m_supports_alloc_dealloc_memory;
+ LazyBool m_supports_memory_region_info;
+ LazyBool m_supports_watchpoint_support_info;
+ LazyBool m_supports_detach_stay_stopped;
+ LazyBool m_watchpoints_trigger_after_instruction;
+ LazyBool m_attach_or_wait_reply;
+ LazyBool m_prepare_for_reg_writing_reply;
+ LazyBool m_supports_p;
+ LazyBool m_supports_x;
+ LazyBool m_avoid_g_packets;
+ LazyBool m_supports_QSaveRegisterState;
+ LazyBool m_supports_qXfer_auxv_read;
+ LazyBool m_supports_qXfer_libraries_read;
+ LazyBool m_supports_qXfer_libraries_svr4_read;
+ LazyBool m_supports_qXfer_features_read;
+ LazyBool m_supports_augmented_libraries_svr4_read;
+ LazyBool m_supports_jThreadExtendedInfo;
bool
m_supports_qProcessInfoPID:1,
@@ -592,7 +627,9 @@ protected:
m_supports_z3:1,
m_supports_z4:1,
m_supports_QEnvironment:1,
- m_supports_QEnvironmentHexEncoded:1;
+ m_supports_QEnvironmentHexEncoded:1,
+ m_supports_qSymbol:1,
+ m_supports_jThreadsInfo:1;
lldb::pid_t m_curr_pid;
lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations
@@ -603,8 +640,8 @@ protected:
// If we need to send a packet while the target is running, the m_async_XXX
// member variables take care of making this happen.
- lldb_private::Mutex m_async_mutex;
- lldb_private::Predicate<bool> m_async_packet_predicate;
+ Mutex m_async_mutex;
+ Predicate<bool> m_async_packet_predicate;
std::string m_async_packet;
PacketResult m_async_result;
StringExtractorGDBRemote m_async_response;
@@ -613,8 +650,8 @@ protected:
std::string m_partial_profile_data;
std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map;
- lldb_private::ArchSpec m_host_arch;
- lldb_private::ArchSpec m_process_arch;
+ ArchSpec m_host_arch;
+ ArchSpec m_process_arch;
uint32_t m_os_version_major;
uint32_t m_os_version_minor;
uint32_t m_os_version_update;
@@ -625,10 +662,11 @@ protected:
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
+
bool
DecodeProcessInfoResponse (StringExtractorGDBRemote &response,
- lldb_private::ProcessInstanceInfo &process_info);
+ ProcessInstanceInfo &process_info);
private:
//------------------------------------------------------------------
// For GDBRemoteCommunicationClient only
@@ -636,4 +674,7 @@ private:
DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationClient);
};
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
#endif // liblldb_GDBRemoteCommunicationClient_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index dd920c0df0ca..13ce9b2dc5c3 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -12,133 +12,35 @@
#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/Debugger.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/State.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/ConnectionFileDescriptor.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/StringConvert.h"
-#include "lldb/Host/TimeValue.h"
-#include "lldb/Target/FileAction.h"
-#include "lldb/Target/Platform.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Host/common/NativeRegisterContext.h"
-#include "lldb/Host/common/NativeProcessProtocol.h"
-#include "lldb/Host/common/NativeThreadProtocol.h"
// Project includes
-#include "Utility/StringExtractorGDBRemote.h"
-#include "Utility/UriParser.h"
-#include "ProcessGDBRemote.h"
#include "ProcessGDBRemoteLog.h"
+#include "Utility/StringExtractorGDBRemote.h"
using namespace lldb;
using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
-//----------------------------------------------------------------------
-// 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) :
- GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform),
- m_platform_sp (Platform::GetHostPlatform ()),
- m_async_thread (LLDB_INVALID_HOST_THREAD),
- m_process_launch_info (),
- m_process_launch_error (),
- m_spawned_pids (),
- m_spawned_pids_mutex (Mutex::eMutexTypeRecursive),
- m_proc_infos (),
- m_proc_infos_index (0),
- m_port_map (),
- 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)
+GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(const char *comm_name,
+ const char *listener_name) :
+ GDBRemoteCommunication (comm_name, listener_name),
+ m_exit_now (false)
{
- assert(is_platform && "must be lldb-platform if debugger is not specified");
}
-GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform,
- 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),
- m_process_launch_info (),
- m_process_launch_error (),
- m_spawned_pids (),
- m_spawned_pids_mutex (Mutex::eMutexTypeRecursive),
- m_proc_infos (),
- m_proc_infos_index (0),
- m_port_map (),
- 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)
+GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer()
{
- assert(platform_sp);
- assert((is_platform || debugger_sp) && "must specify non-NULL debugger_sp when lldb-gdbserver");
}
-//----------------------------------------------------------------------
-// Destructor
-//----------------------------------------------------------------------
-GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer()
+void GDBRemoteCommunicationServer::RegisterPacketHandler(
+ StringExtractorGDBRemote::ServerPacketType packet_type,
+ PacketHandler handler)
{
+ m_packet_handlers[packet_type] = std::move(handler);
}
GDBRemoteCommunication::PacketResult
@@ -149,7 +51,7 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
{
StringExtractorGDBRemote packet;
- PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec);
+ PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec, false);
if (packet_result == PacketResult::Success)
{
const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();
@@ -164,288 +66,16 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
quit = true;
break;
- default:
case StringExtractorGDBRemote::eServerPacketType_unimplemented:
packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
break;
- case StringExtractorGDBRemote::eServerPacketType_A:
- packet_result = Handle_A (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo:
- packet_result = Handle_qfProcessInfo (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo:
- packet_result = Handle_qsProcessInfo (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qC:
- packet_result = Handle_qC (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qHostInfo:
- packet_result = Handle_qHostInfo (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer:
- packet_result = Handle_qLaunchGDBServer (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess:
- packet_result = Handle_qKillSpawnedProcess (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_k:
- packet_result = Handle_k (packet);
- quit = true;
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
- packet_result = Handle_qLaunchSuccess (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qGroupName:
- 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;
-
- case StringExtractorGDBRemote::eServerPacketType_qSpeedTest:
- packet_result = Handle_qSpeedTest (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qUserName:
- packet_result = Handle_qUserName (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir:
- packet_result = Handle_qGetWorkingDir(packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_QEnvironment:
- packet_result = Handle_QEnvironment (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_QLaunchArch:
- packet_result = Handle_QLaunchArch (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR:
- 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;
-
- case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT:
- packet_result = Handle_QSetSTDOUT (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR:
- packet_result = Handle_QSetSTDERR (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir:
- packet_result = Handle_QSetWorkingDir (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode:
- packet_result = Handle_QStartNoAckMode (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir:
- packet_result = Handle_qPlatform_mkdir (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod:
- packet_result = Handle_qPlatform_chmod (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell:
- packet_result = Handle_qPlatform_shell (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo:
- packet_result = Handle_qWatchpointSupportInfo (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;
-
- case StringExtractorGDBRemote::eServerPacketType_vFile_close:
- packet_result = Handle_vFile_Close (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_vFile_pread:
- packet_result = Handle_vFile_pRead (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite:
- packet_result = Handle_vFile_pWrite (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_vFile_size:
- packet_result = Handle_vFile_Size (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_vFile_mode:
- packet_result = Handle_vFile_Mode (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_vFile_exists:
- packet_result = Handle_vFile_Exists (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_vFile_stat:
- packet_result = Handle_vFile_Stat (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_vFile_md5:
- packet_result = Handle_vFile_MD5 (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_vFile_symlink:
- packet_result = Handle_vFile_symlink (packet);
- break;
-
- 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_I:
- packet_result = Handle_I (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);
+ default:
+ auto handler_it = m_packet_handlers.find(packet_type);
+ if (handler_it == m_packet_handlers.end())
+ packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
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;
-
- case StringExtractorGDBRemote::eServerPacketType_D:
- packet_result = Handle_D (packet);
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo:
- packet_result = Handle_qThreadStopInfo (packet);
+ packet_result = handler_it->second (packet, error, interrupt, quit);
break;
}
}
@@ -469,729 +99,6 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
return packet_result;
}
-lldb_private::Error
-GDBRemoteCommunicationServer::SetLaunchArguments (const char *const args[], int argc)
-{
- if ((argc < 1) || !args || !args[0] || !args[0][0])
- return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__);
-
- m_process_launch_info.SetArguments (const_cast<const char**> (args), true);
- return lldb_private::Error ();
-}
-
-lldb_private::Error
-GDBRemoteCommunicationServer::SetLaunchFlags (unsigned int launch_flags)
-{
- m_process_launch_info.GetFlags ().Set (launch_flags);
- return lldb_private::Error ();
-}
-
-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 LaunchProcessForDebugging ();
- else
- return LaunchPlatformProcess ();
-}
-
-bool
-GDBRemoteCommunicationServer::ShouldRedirectInferiorOutputOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const
-{
- // Retrieve the file actions specified for stdout and stderr.
- auto stdout_file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
- auto stderr_file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
-
- // If neither stdout and stderr file actions are specified, we're not doing anything special, so
- // assume we want to redirect stdout/stderr over gdb-remote $O messages.
- if ((stdout_file_action == nullptr) && (stderr_file_action == nullptr))
- {
- // Send stdout/stderr over the gdb-remote protocol.
- return true;
- }
-
- // Any other setting for either stdout or stderr implies we are either suppressing
- // it (with /dev/null) or we've got it set to a PTY. Either way, we don't want the
- // output over gdb-remote.
- return false;
-}
-
-lldb_private::Error
-GDBRemoteCommunicationServer::LaunchProcessForDebugging ()
-{
- 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;
- }
-
- // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol as needed.
- // llgs local-process debugging may specify PTYs, which will eliminate the need to reflect inferior
- // stdout/stderr over the gdb-remote protocol.
- if (ShouldRedirectInferiorOutputOverGdbRemote (m_process_launch_info))
- {
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " setting up stdout/stderr redirection via $O gdb-remote commands", __FUNCTION__, m_debugged_process_sp->GetID ());
-
- // Setup stdout/stderr mapping from inferior to $O
- 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);
- }
- }
- else
- {
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " skipping stdout/stderr redirection via $O: inferior will communicate over client-provided file descriptors", __FUNCTION__, m_debugged_process_sp->GetID ());
- }
-
- 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);
- }
-
- 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__);
-
- // specify the process monitor if not already set. This should
- // generally be what happens since we need to reap started
- // processes.
- if (!m_process_launch_info.GetMonitorProcessCallback ())
- m_process_launch_info.SetMonitorProcessCallback(ReapDebuggedProcess, this, false);
-
- lldb_private::Error error = m_platform_sp->LaunchProcess (m_process_launch_info);
- if (!error.Success ())
- {
- fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0));
- return error;
- }
-
- 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. On an lldb-gdbserver, we
- // would expect there to be only one.
- const auto pid = m_process_launch_info.GetProcessID();
- if (pid != 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:
- 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;
- std::string description;
- if (!thread_sp->GetStopReason (tid_stop_info, description))
- return SendErrorResponse (52);
-
- // FIXME implement register handling for exec'd inferiors.
- // if (tid_stop_info.reason == eStopReasonExec)
- // {
- // 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);
- }
-
- // 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 std::string thread_name = thread_sp->GetName ();
- if (!thread_name.empty ())
- {
- size_t thread_name_len = thread_name.length ();
-
- if (::strcspn (thread_name.c_str (), "$#+-;:") == thread_name_len)
- {
- response.PutCString ("name:");
- response.PutCString (thread_name.c_str ());
- }
- else
- {
- // The thread name contains special chars, send as hex bytes.
- response.PutCString ("hexname:");
- response.PutCStringAsRawHex8 (thread_name.c_str ());
- }
- response.PutChar (';');
- }
-
- // 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 ());
-
- }
- }
- }
- }
- }
-
- const char* reason_str = nullptr;
- switch (tid_stop_info.reason)
- {
- case eStopReasonTrace:
- reason_str = "trace";
- break;
- case eStopReasonBreakpoint:
- reason_str = "breakpoint";
- break;
- case eStopReasonWatchpoint:
- reason_str = "watchpoint";
- break;
- case eStopReasonSignal:
- reason_str = "signal";
- break;
- case eStopReasonException:
- reason_str = "exception";
- break;
- case eStopReasonExec:
- reason_str = "exec";
- break;
- case eStopReasonInstrumentation:
- case eStopReasonInvalid:
- case eStopReasonPlanComplete:
- case eStopReasonThreadExiting:
- case eStopReasonNone:
- break;
- }
- if (reason_str != nullptr)
- {
- response.Printf ("reason:%s;", reason_str);
- }
-
- if (!description.empty())
- {
- // Description may contains special chars, send as hex bytes.
- response.PutCString ("description:");
- response.PutCStringAsRawHex8 (description.c_str ());
- response.PutChar (';');
- }
- 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);
- 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 *)
{
@@ -1229,3334 +136,3 @@ GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr)
{
return GetAck() == PacketResult::Success;
}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet)
-{
- StreamString response;
-
- // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
-
- ArchSpec host_arch(HostInfo::GetArchitecture());
- const llvm::Triple &host_triple = host_arch.GetTriple();
- response.PutCString("triple:");
- response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
- response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
-
- const char* distribution_id = host_arch.GetDistributionId ().AsCString ();
- if (distribution_id)
- {
- response.PutCString("distribution_id:");
- response.PutCStringAsRawHex8(distribution_id);
- 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)
- response.Printf ("cputype:%u;", cpu);
- if (sub != LLDB_INVALID_CPUTYPE)
- response.Printf ("cpusubtype:%u;", sub);
-
- if (cpu == ArchSpec::kCore_arm_any)
- 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())
- {
- case eByteOrderBig: response.PutCString ("endian:big;"); break;
- case eByteOrderLittle: response.PutCString ("endian:little;"); break;
- case eByteOrderPDP: response.PutCString ("endian:pdp;"); break;
- default: response.PutCString ("endian:unknown;"); break;
- }
-
- uint32_t major = UINT32_MAX;
- uint32_t minor = UINT32_MAX;
- uint32_t update = UINT32_MAX;
- if (HostInfo::GetOSVersion(major, minor, update))
- {
- if (major != UINT32_MAX)
- {
- response.Printf("os_version:%u", major);
- if (minor != UINT32_MAX)
- {
- response.Printf(".%u", minor);
- if (update != UINT32_MAX)
- response.Printf(".%u", update);
- }
- response.PutChar(';');
- }
- }
-
- std::string s;
- if (HostInfo::GetOSBuildString(s))
- {
- response.PutCString ("os_build:");
- response.PutCStringAsRawHex8(s.c_str());
- response.PutChar(';');
- }
- if (HostInfo::GetOSKernelDescription(s))
- {
- response.PutCString ("os_kernel:");
- response.PutCStringAsRawHex8(s.c_str());
- response.PutChar(';');
- }
-
-#if defined(__APPLE__)
-
-#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("127.0.0.1");
- response.PutChar(';');
-#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__) || defined(__arm64__) || defined(__aarch64__)
-
-#else // #if defined(__APPLE__)
- if (HostInfo::GetHostname(s))
- {
- response.PutCString ("hostname:");
- response.PutCStringAsRawHex8(s.c_str());
- response.PutChar(';');
- }
-#endif // #if defined(__APPLE__)
-
- return SendPacketNoLock (response.GetData(), response.GetSize());
-}
-
-static void
-CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response)
-{
- response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;",
- proc_info.GetProcessID(),
- proc_info.GetParentProcessID(),
- proc_info.GetUserID(),
- proc_info.GetGroupID(),
- proc_info.GetEffectiveUserID(),
- proc_info.GetEffectiveGroupID());
- response.PutCString ("name:");
- response.PutCStringAsRawHex8(proc_info.GetName());
- response.PutChar(';');
- const ArchSpec &proc_arch = proc_info.GetArchitecture();
- if (proc_arch.IsValid())
- {
- const llvm::Triple &proc_triple = proc_arch.GetTriple();
- response.PutCString("triple:");
- response.PutCStringAsRawHex8(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.PutCString("triple:");
- response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
- response.PutChar(';');
-
-#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)
-{
- lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
-
- 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);
-
- pid = m_debugged_process_sp->GetID ();
- }
- else if (m_is_platform)
- {
- pid = m_process_launch_info.GetProcessID ();
- m_process_launch_info.Clear ();
- }
- else
- return SendUnimplementedResponse (packet.GetStringRef ().c_str ());
-
- if (pid == LLDB_INVALID_PROCESS_ID)
- return SendErrorResponse (1);
-
- ProcessInstanceInfo proc_info;
- if (!Host::GetProcessInfo (pid, proc_info))
- return SendErrorResponse (1);
-
- StreamString response;
- CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
- return SendPacketNoLock (response.GetData (), response.GetSize ());
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
-{
- // Packet format: "qProcessInfoPID:%i" where %i is the pid
- packet.SetFilePos(::strlen ("qProcessInfoPID:"));
- lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID);
- if (pid != LLDB_INVALID_PROCESS_ID)
- {
- ProcessInstanceInfo proc_info;
- if (Host::GetProcessInfo(pid, proc_info))
- {
- StreamString response;
- CreateProcessInfoResponse (proc_info, response);
- return SendPacketNoLock (response.GetData(), response.GetSize());
- }
- }
- return SendErrorResponse (1);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)
-{
- m_proc_infos_index = 0;
- m_proc_infos.Clear();
-
- ProcessInstanceInfoMatch match_info;
- packet.SetFilePos(::strlen ("qfProcessInfo"));
- if (packet.GetChar() == ':')
- {
-
- std::string key;
- std::string value;
- while (packet.GetNameColonValue(key, value))
- {
- bool success = true;
- if (key.compare("name") == 0)
- {
- StringExtractor extractor;
- extractor.GetStringRef().swap(value);
- extractor.GetHexByteString (value);
- match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false);
- }
- else if (key.compare("name_match") == 0)
- {
- if (value.compare("equals") == 0)
- {
- match_info.SetNameMatchType (eNameMatchEquals);
- }
- else if (value.compare("starts_with") == 0)
- {
- match_info.SetNameMatchType (eNameMatchStartsWith);
- }
- else if (value.compare("ends_with") == 0)
- {
- match_info.SetNameMatchType (eNameMatchEndsWith);
- }
- else if (value.compare("contains") == 0)
- {
- match_info.SetNameMatchType (eNameMatchContains);
- }
- else if (value.compare("regex") == 0)
- {
- match_info.SetNameMatchType (eNameMatchRegularExpression);
- }
- else
- {
- success = false;
- }
- }
- else if (key.compare("pid") == 0)
- {
- match_info.GetProcessInfo().SetProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
- }
- else if (key.compare("parent_pid") == 0)
- {
- match_info.GetProcessInfo().SetParentProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
- }
- else if (key.compare("uid") == 0)
- {
- match_info.GetProcessInfo().SetUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
- }
- else if (key.compare("gid") == 0)
- {
- match_info.GetProcessInfo().SetGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
- }
- else if (key.compare("euid") == 0)
- {
- match_info.GetProcessInfo().SetEffectiveUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
- }
- else if (key.compare("egid") == 0)
- {
- match_info.GetProcessInfo().SetEffectiveGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
- }
- else if (key.compare("all_users") == 0)
- {
- match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success));
- }
- else if (key.compare("triple") == 0)
- {
- match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL);
- }
- else
- {
- success = false;
- }
-
- if (!success)
- return SendErrorResponse (2);
- }
- }
-
- if (Host::FindProcesses (match_info, m_proc_infos))
- {
- // We found something, return the first item by calling the get
- // subsequent process info packet handler...
- return Handle_qsProcessInfo (packet);
- }
- return SendErrorResponse (3);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet)
-{
- if (m_proc_infos_index < m_proc_infos.GetSize())
- {
- StreamString response;
- CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response);
- ++m_proc_infos_index;
- return SendPacketNoLock (response.GetData(), response.GetSize());
- }
- return SendErrorResponse (4);
-}
-
-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 (HostInfo::LookupUserName(uid, name))
- {
- StreamString response;
- response.PutCStringAsRawHex8 (name.c_str());
- return SendPacketNoLock (response.GetData(), response.GetSize());
- }
- }
-#endif
- return SendErrorResponse (5);
-
-}
-
-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 (HostInfo::LookupGroupName(gid, name))
- {
- StreamString response;
- response.PutCStringAsRawHex8 (name.c_str());
- return SendPacketNoLock (response.GetData(), response.GetSize());
- }
- }
-#endif
- return SendErrorResponse (6);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("qSpeedTest:"));
-
- std::string key;
- std::string value;
- bool success = packet.GetNameColonValue(key, value);
- if (success && key.compare("response_size") == 0)
- {
- uint32_t response_size = StringConvert::ToUInt32(value.c_str(), 0, 0, &success);
- if (success)
- {
- if (response_size == 0)
- return SendOKResponse();
- StreamString response;
- uint32_t bytes_left = response_size;
- response.PutCString("data:");
- while (bytes_left > 0)
- {
- if (bytes_left >= 26)
- {
- response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
- bytes_left -= 26;
- }
- else
- {
- response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
- bytes_left = 0;
- }
- }
- return SendPacketNoLock (response.GetData(), response.GetSize());
- }
- }
- return SendErrorResponse (7);
-}
-
-//
-//static bool
-//WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
-//{
-// const int time_delta_usecs = 100000;
-// const int num_retries = timeout_in_seconds/time_delta_usecs;
-// for (int i=0; i<num_retries; i++)
-// {
-// struct proc_bsdinfo bsd_info;
-// int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
-// (uint64_t) 0,
-// &bsd_info,
-// PROC_PIDTBSDINFO_SIZE);
-//
-// switch (error)
-// {
-// case EINVAL:
-// case ENOTSUP:
-// case ESRCH:
-// case EPERM:
-// return false;
-//
-// default:
-// break;
-//
-// case 0:
-// if (bsd_info.pbi_status == SSTOP)
-// return true;
-// }
-// ::usleep (time_delta_usecs);
-// }
-// return false;
-//}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
-{
- // The 'A' packet is the most over designed packet ever here with
- // redundant argument indexes, redundant argument lengths and needed hex
- // encoded argument string values. Really all that is needed is a comma
- // 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)
- {
- // Decode the decimal argument string length. This length is the
- // number of hex nibbles in the argument string value.
- const uint32_t arg_len = packet.GetU32(UINT32_MAX);
- if (arg_len == UINT32_MAX)
- success = false;
- else
- {
- // Make sure the argument hex string length is followed by a comma
- if (packet.GetChar() != ',')
- success = false;
- else
- {
- // 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)
- success = false;
- else
- {
- // Make sure the argument index is followed by a comma
- if (packet.GetChar() != ',')
- success = false;
- else
- {
- // Decode the argument string value from hex bytes
- // back into a UTF8 string and make sure the length
- // matches the one supplied in the packet
- std::string arg;
- if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2))
- success = false;
- else
- {
- // If there are any bytes left
- if (packet.GetBytesLeft())
- {
- if (packet.GetChar() != ',')
- success = false;
- }
-
- if (success)
- {
- 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;
- }
- }
- }
- }
- }
- }
- }
-
- if (success)
- {
- 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);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
-{
- StreamString response;
-
- 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
- {
- // 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)
- {
- // 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());
-}
-
-bool
-GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid)
-{
- Mutex::Locker locker (m_spawned_pids_mutex);
- FreePortForProcess(pid);
- return m_spawned_pids.erase(pid) > 0;
-}
-bool
-GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton,
- lldb::pid_t pid,
- bool exited,
- int signal, // Zero for no signal
- int status) // Exit value of process if signal is zero
-{
- GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
- server->DebugserverProcessReaped (pid);
- return true;
-}
-
-bool
-GDBRemoteCommunicationServer::DebuggedProcessReaped (lldb::pid_t pid)
-{
- // reap a process that we were debugging (but not debugserver)
- Mutex::Locker locker (m_spawned_pids_mutex);
- return m_spawned_pids.erase(pid) > 0;
-}
-
-bool
-GDBRemoteCommunicationServer::ReapDebuggedProcess (void *callback_baton,
- lldb::pid_t pid,
- bool exited,
- int signal, // Zero for no signal
- int status) // Exit value of process if signal is zero
-{
- GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
- server->DebuggedProcessReaped (pid);
- return true;
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
-{
-#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;
- std::string hostname;
- // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
- // with the TMPDIR environment variable
- packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
- std::string name;
- std::string value;
- uint16_t port = UINT16_MAX;
- while (packet.GetNameColonValue(name, value))
- {
- if (name.compare ("host") == 0)
- hostname.swap(value);
- else if (name.compare ("port") == 0)
- port = StringConvert::ToUInt32(value.c_str(), 0, 0);
- }
- if (port == UINT16_MAX)
- port = GetNextAvailablePort();
-
- // Spawn a new thread to accept the port that gets bound after
- // binding to port 0 (zero).
-
- // ignore the hostname send from the remote end, just use the ip address
- // that we're currently communicating with as the hostname
-
- // 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);
-
- // Do not run in a new session so that it can not linger after the
- // platform closes.
- debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
- debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
-
- std::string platform_scheme;
- std::string platform_ip;
- int platform_port;
- std::string platform_path;
- bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path);
- assert(ok);
- Error error = StartDebugserverProcess (
- platform_ip.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())
- {
- 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);
-#endif
-}
-
-bool
-GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid)
-{
- // make sure we know about this process
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- return false;
- }
-
- // first try a SIGTERM (standard kill)
- Host::Kill (pid, SIGTERM);
-
- // check if that worked
- for (size_t i=0; i<10; ++i)
- {
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- {
- // it is now killed
- return true;
- }
- }
- usleep (10000);
- }
-
- // check one more time after the final usleep
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- return true;
- }
-
- // the launched process still lives. Now try killing it again,
- // this time with an unblockable signal.
- Host::Kill (pid, SIGKILL);
-
- for (size_t i=0; i<10; ++i)
- {
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- {
- // it is now killed
- return true;
- }
- }
- usleep (10000);
- }
-
- // check one more time after the final usleep
- // Scope for locker
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- return true;
- }
-
- // no luck - the process still lives
- return false;
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
-
- lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
-
- // verify that we know anything about this pid.
- // Scope for locker
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- {
- // not a pid we know about
- return SendErrorResponse (10);
- }
- }
-
- // go ahead and attempt to kill the spawned process
- if (KillSpawnedProcess (pid))
- return SendOKResponse ();
- else
- return SendErrorResponse (11);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet)
-{
- // ignore for now if we're lldb_platform
- if (m_is_platform)
- return SendUnimplementedResponse (packet.GetStringRef().c_str());
-
- // shutdown all spawned processes
- std::set<lldb::pid_t> spawned_pids_copy;
-
- // copy pids
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ());
- }
-
- // nuke the spawned processes
- for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it)
- {
- lldb::pid_t spawned_pid = *it;
- if (!KillSpawnedProcess (spawned_pid))
- {
- fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid);
- }
- }
-
- FlushInferiorOutput ();
-
- // No OK response for kill packet.
- // return SendOKResponse ();
- return PacketResult::Success;
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
-{
- if (m_process_launch_error.Success())
- return SendOKResponse();
- StreamString response;
- response.PutChar('E');
- response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
- return SendPacketNoLock (response.GetData(), response.GetSize());
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QEnvironment:"));
- const uint32_t bytes_left = packet.GetBytesLeft();
- if (bytes_left > 0)
- {
- m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
- return SendOKResponse ();
- }
- return SendErrorResponse (12);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QLaunchArch:"));
- const uint32_t bytes_left = packet.GetBytesLeft();
- if (bytes_left > 0)
- {
- const char* arch_triple = packet.Peek();
- ArchSpec arch_spec(arch_triple,NULL);
- m_process_launch_info.SetArchitecture(arch_spec);
- return SendOKResponse();
- }
- return SendErrorResponse(13);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QSetDisableASLR:"));
- if (packet.GetU32(0))
- m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
- else
- m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
- return SendOKResponse ();
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QSetWorkingDir:"));
- std::string path;
- packet.GetHexByteString(path);
- if (m_is_platform)
- {
-#ifdef _WIN32
- // Not implemented on Windows
- return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_QSetWorkingDir unimplemented");
-#else
- // If this packet is sent to a platform, then change the current working directory
- if (::chdir(path.c_str()) != 0)
- return SendErrorResponse(errno);
-#endif
- }
- else
- {
- m_process_launch_info.SwapWorkingDirectory (path);
- }
- return SendOKResponse ();
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
-{
- StreamString response;
-
- if (m_is_platform)
- {
- // If this packet is sent to a platform, then change the current working directory
- char cwd[PATH_MAX];
- if (getcwd(cwd, sizeof(cwd)) == NULL)
- {
- return SendErrorResponse(errno);
- }
- else
- {
- response.PutBytesAsRawHex8(cwd, strlen(cwd));
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
- }
- else
- {
- const char *working_dir = m_process_launch_info.GetWorkingDirectory();
- if (working_dir && working_dir[0])
- {
- response.PutBytesAsRawHex8(working_dir, strlen(working_dir));
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
- else
- {
- return SendErrorResponse(14);
- }
- }
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QSetSTDIN:"));
- FileAction file_action;
- std::string path;
- packet.GetHexByteString(path);
- const bool read = false;
- const bool write = true;
- if (file_action.Open(STDIN_FILENO, path.c_str(), read, write))
- {
- m_process_launch_info.AppendFileAction(file_action);
- return SendOKResponse ();
- }
- return SendErrorResponse (15);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QSetSTDOUT:"));
- FileAction file_action;
- std::string path;
- packet.GetHexByteString(path);
- const bool read = true;
- const bool write = false;
- if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write))
- {
- m_process_launch_info.AppendFileAction(file_action);
- return SendOKResponse ();
- }
- return SendErrorResponse (16);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QSetSTDERR:"));
- FileAction file_action;
- std::string path;
- packet.GetHexByteString(path);
- const bool read = true;
- const bool write = false;
- if (file_action.Open(STDERR_FILENO, path.c_str(), read, write))
- {
- m_process_launch_info.AppendFileAction(file_action);
- return SendOKResponse ();
- }
- return SendErrorResponse (17);
-}
-
-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());
- }
-
- 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);
- }
-
- 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
- PacketResult packet_result = SendOKResponse ();
- m_send_acks = false;
- return packet_result;
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("qPlatform_mkdir:"));
- mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
- if (packet.GetChar() == ',')
- {
- std::string path;
- packet.GetHexByteString(path);
- Error error = FileSystem::MakeDirectory(path.c_str(), mode);
- if (error.Success())
- return SendPacketNoLock ("OK", 2);
- else
- return SendErrorResponse(error.GetError());
- }
- return SendErrorResponse(20);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("qPlatform_chmod:"));
-
- mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
- if (packet.GetChar() == ',')
- {
- std::string path;
- packet.GetHexByteString(path);
- Error error = FileSystem::SetFilePermissions(path.c_str(), mode);
- if (error.Success())
- return SendPacketNoLock ("OK", 2);
- else
- return SendErrorResponse(error.GetError());
- }
- return SendErrorResponse(19);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:open:"));
- std::string path;
- packet.GetHexByteStringTerminatedBy(path,',');
- if (!path.empty())
- {
- if (packet.GetChar() == ',')
- {
- uint32_t flags = packet.GetHexMaxU32(false, 0);
- if (packet.GetChar() == ',')
- {
- mode_t mode = packet.GetHexMaxU32(false, 0600);
- Error error;
- int fd = ::open (path.c_str(), flags, mode);
- const int save_errno = fd == -1 ? errno : 0;
- StreamString response;
- response.PutChar('F');
- response.Printf("%i", fd);
- if (save_errno)
- response.Printf(",%i", save_errno);
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
- }
- }
- return SendErrorResponse(18);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:close:"));
- int fd = packet.GetS32(-1);
- Error error;
- int err = -1;
- int save_errno = 0;
- if (fd >= 0)
- {
- err = close(fd);
- save_errno = err == -1 ? errno : 0;
- }
- else
- {
- save_errno = EINVAL;
- }
- StreamString response;
- response.PutChar('F');
- response.Printf("%i", err);
- if (save_errno)
- response.Printf(",%i", save_errno);
- return SendPacketNoLock(response.GetData(), response.GetSize());
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet)
-{
-#ifdef _WIN32
- // Not implemented on Windows
- return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented");
-#else
- StreamGDBRemote response;
- packet.SetFilePos(::strlen("vFile:pread:"));
- int fd = packet.GetS32(-1);
- if (packet.GetChar() == ',')
- {
- uint64_t count = packet.GetU64(UINT64_MAX);
- if (packet.GetChar() == ',')
- {
- uint64_t offset = packet.GetU64(UINT32_MAX);
- if (count == UINT64_MAX)
- {
- response.Printf("F-1:%i", EINVAL);
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
-
- std::string buffer(count, 0);
- const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
- const int save_errno = bytes_read == -1 ? errno : 0;
- response.PutChar('F');
- response.Printf("%zi", bytes_read);
- if (save_errno)
- response.Printf(",%i", save_errno);
- else
- {
- response.PutChar(';');
- response.PutEscapedBytes(&buffer[0], bytes_read);
- }
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
- }
- return SendErrorResponse(21);
-
-#endif
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
-{
-#ifdef _WIN32
- return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pWrite() unimplemented");
-#else
- packet.SetFilePos(::strlen("vFile:pwrite:"));
-
- StreamGDBRemote response;
- response.PutChar('F');
-
- int fd = packet.GetU32(UINT32_MAX);
- if (packet.GetChar() == ',')
- {
- off_t offset = packet.GetU64(UINT32_MAX);
- if (packet.GetChar() == ',')
- {
- std::string buffer;
- if (packet.GetEscapedBinaryData(buffer))
- {
- const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
- const int save_errno = bytes_written == -1 ? errno : 0;
- response.Printf("%zi", bytes_written);
- if (save_errno)
- response.Printf(",%i", save_errno);
- }
- else
- {
- response.Printf ("-1,%i", EINVAL);
- }
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
- }
- return SendErrorResponse(27);
-#endif
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:size:"));
- std::string path;
- packet.GetHexByteString(path);
- if (!path.empty())
- {
- lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path.c_str(), false));
- StreamString response;
- response.PutChar('F');
- response.PutHex64(retcode);
- if (retcode == UINT64_MAX)
- {
- response.PutChar(',');
- response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
- }
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
- return SendErrorResponse(22);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:mode:"));
- std::string path;
- packet.GetHexByteString(path);
- if (!path.empty())
- {
- Error error;
- const uint32_t mode = File::GetPermissions(path.c_str(), error);
- StreamString response;
- response.Printf("F%u", mode);
- if (mode == 0 || error.Fail())
- response.Printf(",%i", (int)error.GetError());
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
- return SendErrorResponse(23);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:exists:"));
- std::string path;
- packet.GetHexByteString(path);
- if (!path.empty())
- {
- bool retcode = FileSystem::GetFileExists(FileSpec(path.c_str(), false));
- StreamString response;
- response.PutChar('F');
- response.PutChar(',');
- if (retcode)
- response.PutChar('1');
- else
- response.PutChar('0');
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
- return SendErrorResponse(24);
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:symlink:"));
- std::string dst, src;
- packet.GetHexByteStringTerminatedBy(dst, ',');
- packet.GetChar(); // Skip ',' char
- packet.GetHexByteString(src);
- 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());
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:unlink:"));
- std::string path;
- packet.GetHexByteString(path);
- Error error = FileSystem::Unlink(path.c_str());
- StreamString response;
- response.Printf("F%u,%u", error.GetError(), error.GetError());
- return SendPacketNoLock(response.GetData(), response.GetSize());
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("qPlatform_shell:"));
- std::string path;
- std::string working_dir;
- packet.GetHexByteStringTerminatedBy(path,',');
- if (!path.empty())
- {
- if (packet.GetChar() == ',')
- {
- // FIXME: add timeout to qPlatform_shell packet
- // uint32_t timeout = packet.GetHexMaxU32(false, 32);
- uint32_t timeout = 10;
- if (packet.GetChar() == ',')
- packet.GetHexByteString(working_dir);
- int status, signo;
- std::string output;
- Error err = Host::RunShellCommand(path.c_str(),
- working_dir.empty() ? NULL : working_dir.c_str(),
- &status, &signo, &output, timeout);
- StreamGDBRemote response;
- if (err.Fail())
- {
- response.PutCString("F,");
- response.PutHex32(UINT32_MAX);
- }
- else
- {
- response.PutCString("F,");
- response.PutHex32(status);
- response.PutChar(',');
- response.PutHex32(signo);
- response.PutChar(',');
- response.PutEscapedBytes(output.c_str(), output.size());
- }
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
- }
- 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)
-{
- return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented");
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:MD5:"));
- std::string path;
- packet.GetHexByteString(path);
- if (!path.empty())
- {
- uint64_t a,b;
- StreamGDBRemote response;
- if (FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b) == false)
- {
- response.PutCString("F,");
- response.PutCString("x");
- }
- else
- {
- response.PutCString("F,");
- response.PutHex64(a);
- response.PutHex64(b);
- }
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
- 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->GetUserRegisterCount ())
- 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->GetUserRegisterCount ())
- {
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ());
- 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.
- uint8_t reg_bytes[32]; // big enough to support up to 256 bit ymmN register
- size_t reg_size = packet.GetHexBytesAvail (reg_bytes, sizeof(reg_bytes));
-
- // 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->GetUserRegisterCount ())
- {
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ());
- return SendErrorResponse (0x47);
- }
-
- if (reg_size != reg_info->byte_size)
- {
- return SendIllFormedResponse (packet, "P packet register size is incorrect");
- }
-
- // Build the reginfos response.
- StreamGDBRemote response;
-
- RegisterValue reg_value (reg_bytes, reg_size, process_arch.GetByteOrder ());
- Error error = reg_context_sp->WriteRegister (reg_info, reg_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_I (StringExtractorGDBRemote &packet)
-{
- Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
-
- // Ensure we're llgs.
- if (!IsGdbServer())
- return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_I() 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);
- }
-
- packet.SetFilePos (::strlen("I"));
- char tmp[4096];
- for (;;)
- {
- size_t read = packet.GetHexBytesAvail(tmp, sizeof(tmp));
- if (read == 0)
- {
- break;
- }
- // write directly to stdin *this might block if stdin buffer is full*
- // TODO: enqueue this block in circular buffer and send window size to remote host
- ConnectionStatus status;
- Error error;
- m_stdio_communication.Write(tmp, read, status, &error);
- if (error.Fail())
- {
- return SendErrorResponse (0x15);
- }
- }
-
- 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);
- }
-
- // Interrupt the process.
- Error error = m_debugged_process_sp->Interrupt ();
- 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)
-{
- // 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))
- {
- Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
- return SendErrorResponse (0x15);
- }
-
- // Parse out software or hardware breakpoint or watchpoint 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 GDBStoppointType stoppoint_type =
- GDBStoppointType(packet.GetS32 (eStoppointInvalid));
- switch (stoppoint_type)
- {
- case eBreakpointSoftware:
- want_hardware = false; want_breakpoint = true; break;
- case eBreakpointHardware:
- want_hardware = true; want_breakpoint = true; break;
- case eWatchpointWrite:
- want_hardware = true; want_breakpoint = false; break;
- case eWatchpointRead:
- want_hardware = true; want_breakpoint = false; break;
- case eWatchpointReadWrite:
- want_hardware = true; want_breakpoint = false; break;
- case eStoppointInvalid:
- 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 stoppoint type");
-
- // Parse out the stoppoint address.
- if (packet.GetBytesLeft() < 1)
- return SendIllFormedResponse(packet, "Too short Z packet, missing address");
- const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
-
- if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
- return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address");
-
- // Parse out the stoppoint size (i.e. size hint for opcode size).
- const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
- if (size == std::numeric_limits<uint32_t>::max ())
- return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse size argument");
-
- if (want_breakpoint)
- {
- // Try to set the breakpoint.
- const Error error = m_debugged_process_sp->SetBreakpoint (addr, size, want_hardware);
- if (error.Success ())
- return SendOKResponse ();
- Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64
- " failed to set breakpoint: %s",
- __FUNCTION__,
- m_debugged_process_sp->GetID (),
- error.AsCString ());
- return SendErrorResponse (0x09);
- }
- else
- {
- uint32_t watch_flags =
- stoppoint_type == eWatchpointWrite
- ? watch_flags = 0x1 // Write
- : watch_flags = 0x3; // ReadWrite
-
- // Try to set the watchpoint.
- const Error error = m_debugged_process_sp->SetWatchpoint (
- addr, size, watch_flags, want_hardware);
- if (error.Success ())
- return SendOKResponse ();
- Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64
- " failed to set watchpoint: %s",
- __FUNCTION__,
- m_debugged_process_sp->GetID (),
- error.AsCString ());
- return SendErrorResponse (0x09);
- }
-}
-
-GDBRemoteCommunicationServer::PacketResult
-GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet)
-{
- // 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))
- {
- Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
- return SendErrorResponse (0x15);
- }
-
- // Parse out software or hardware breakpoint or watchpoint 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 GDBStoppointType stoppoint_type =
- GDBStoppointType(packet.GetS32 (eStoppointInvalid));
- switch (stoppoint_type)
- {
- case eBreakpointHardware: want_breakpoint = true; break;
- case eBreakpointSoftware: want_breakpoint = true; break;
- case eWatchpointWrite: want_breakpoint = false; break;
- case eWatchpointRead: want_breakpoint = false; break;
- case eWatchpointReadWrite: 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 stoppoint type");
-
- // Parse out the stoppoint address.
- if (packet.GetBytesLeft() < 1)
- return SendIllFormedResponse(packet, "Too short z packet, missing address");
- const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
-
- if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
- return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address");
-
- /*
- // Parse out the stoppoint size (i.e. size hint for opcode size).
- const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
- if (size == std::numeric_limits<uint32_t>::max ())
- return SendIllFormedResponse(packet, "Malformed z packet, failed to parse size argument");
- */
-
- if (want_breakpoint)
- {
- // Try to clear the breakpoint.
- const Error error = m_debugged_process_sp->RemoveBreakpoint (addr);
- if (error.Success ())
- return SendOKResponse ();
- Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64
- " failed to remove breakpoint: %s",
- __FUNCTION__,
- m_debugged_process_sp->GetID (),
- error.AsCString ());
- return SendErrorResponse (0x09);
- }
- else
- {
- // Try to clear the watchpoint.
- const Error error = m_debugged_process_sp->RemoveWatchpoint (addr);
- if (error.Success ())
- return SendOKResponse ();
- Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64
- " failed to remove watchpoint: %s",
- __FUNCTION__,
- m_debugged_process_sp->GetID (),
- error.AsCString ());
- return SendErrorResponse (0x09);
- }
-}
-
-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);
-}
-
-GDBRemoteCommunicationServer::PacketResult
-GDBRemoteCommunicationServer::Handle_D (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");
-
- // Scope for mutex locker.
- Mutex::Locker locker (m_spawned_pids_mutex);
-
- // 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);
- }
-
- if (m_spawned_pids.find(m_debugged_process_sp->GetID ()) == m_spawned_pids.end())
- {
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s failed to find PID %" PRIu64 " in spawned pids list",
- __FUNCTION__, m_debugged_process_sp->GetID ());
- return SendErrorResponse (0x1);
- }
-
- lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
-
- // Consume the ';' after D.
- packet.SetFilePos (1);
- if (packet.GetBytesLeft ())
- {
- if (packet.GetChar () != ';')
- return SendIllFormedResponse (packet, "D missing expected ';'");
-
- // Grab the PID from which we will detach (assume hex encoding).
- pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16);
- if (pid == LLDB_INVALID_PROCESS_ID)
- return SendIllFormedResponse (packet, "D failed to parse the process id");
- }
-
- if (pid != LLDB_INVALID_PROCESS_ID &&
- m_debugged_process_sp->GetID () != pid)
- {
- return SendIllFormedResponse (packet, "Invalid pid");
- }
-
- if (m_stdio_communication.IsConnected ())
- {
- m_stdio_communication.StopReadThread ();
- }
-
- const Error error = m_debugged_process_sp->Detach ();
- if (error.Fail ())
- {
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s failed to detach from pid %" PRIu64 ": %s\n",
- __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
- return SendErrorResponse (0x01);
- }
-
- m_spawned_pids.erase (m_debugged_process_sp->GetID ());
- return SendOKResponse ();
-}
-
-GDBRemoteCommunicationServer::PacketResult
-GDBRemoteCommunicationServer::Handle_qThreadStopInfo (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");
-
- packet.SetFilePos (strlen("qThreadStopInfo"));
- const lldb::tid_t tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID);
- if (tid == LLDB_INVALID_THREAD_ID)
- {
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse thread id from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ());
- return SendErrorResponse (0x15);
- }
- return SendStopReplyPacketForThread (tid);
-}
-
-GDBRemoteCommunicationServer::PacketResult
-GDBRemoteCommunicationServer::Handle_qWatchpointSupportInfo (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);
-
- packet.SetFilePos(strlen("qWatchpointSupportInfo"));
- if (packet.GetBytesLeft() == 0)
- return SendOKResponse();
- if (packet.GetChar() != ':')
- return SendErrorResponse(67);
-
- uint32_t num = m_debugged_process_sp->GetMaxWatchpoints();
- StreamGDBRemote response;
- response.Printf ("num:%d;", num);
- return SendPacketNoLock(response.GetData(), response.GetSize());
-}
-
-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 dcf07844527e..992c6dffaf54 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -12,236 +12,53 @@
// C Includes
// C++ Includes
-#include <vector>
-#include <set>
-#include <unordered_map>
+#include <functional>
+#include <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 "lldb/Host/common/NativeProcessProtocol.h"
+class StringExtractorGDBRemote;
+
+namespace lldb_private {
+namespace process_gdb_remote {
class ProcessGDBRemote;
-class StringExtractorGDBRemote;
-class GDBRemoteCommunicationServer :
- public GDBRemoteCommunication,
- public lldb_private::NativeProcessProtocol::NativeDelegate
+class GDBRemoteCommunicationServer : public GDBRemoteCommunication
{
public:
- typedef std::map<uint16_t, lldb::pid_t> PortMap;
-
- enum
- {
- eBroadcastBitRunPacketSent = kLoUserBroadcastBit
- };
- //------------------------------------------------------------------
- // Constructors and Destructors
- //------------------------------------------------------------------
- GDBRemoteCommunicationServer(bool is_platform);
+ using PortMap = std::map<uint16_t, lldb::pid_t>;
+ using PacketHandler = std::function<PacketResult(StringExtractorGDBRemote &packet,
+ Error &error,
+ bool &interrupt,
+ bool &quit)>;
- GDBRemoteCommunicationServer(bool is_platform,
- const lldb::PlatformSP& platform_sp,
- lldb::DebuggerSP& debugger_sp);
+ GDBRemoteCommunicationServer(const char *comm_name,
+ const char *listener_name);
virtual
~GDBRemoteCommunicationServer();
+ void RegisterPacketHandler(StringExtractorGDBRemote::ServerPacketType packet_type,
+ PacketHandler handler);
+
PacketResult
GetPacketAndSendResponse (uint32_t timeout_usec,
- lldb_private::Error &error,
+ Error &error,
bool &interrupt,
bool &quit);
- virtual bool
- GetThreadSuffixSupported () override
- {
- return true;
- }
-
// After connecting, do a little handshake with the client to make sure
// we are at least communicating
bool
- HandshakeWithClient (lldb_private::Error *error_ptr);
-
- // Set both ports to zero to let the platform automatically bind to
- // a port chosen by the OS.
- void
- SetPortMap (PortMap &&port_map)
- {
- m_port_map = port_map;
- }
-
- //----------------------------------------------------------------------
- // If we are using a port map where we can only use certain ports,
- // get the next available port.
- //
- // If we are using a port map and we are out of ports, return UINT16_MAX
- //
- // If we aren't using a port map, return 0 to indicate we should bind to
- // port 0 and then figure out which port we used.
- //----------------------------------------------------------------------
- uint16_t
- GetNextAvailablePort ()
- {
- if (m_port_map.empty())
- return 0; // Bind to port zero and get a port, we didn't have any limitations
-
- for (auto &pair : m_port_map)
- {
- if (pair.second == LLDB_INVALID_PROCESS_ID)
- {
- pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
- return pair.first;
- }
- }
- return UINT16_MAX;
- }
-
- bool
- AssociatePortWithProcess (uint16_t port, lldb::pid_t pid)
- {
- PortMap::iterator pos = m_port_map.find(port);
- if (pos != m_port_map.end())
- {
- pos->second = pid;
- return true;
- }
- return false;
- }
-
- bool
- FreePort (uint16_t port)
- {
- PortMap::iterator pos = m_port_map.find(port);
- if (pos != m_port_map.end())
- {
- pos->second = LLDB_INVALID_PROCESS_ID;
- return true;
- }
- return false;
- }
-
- bool
- FreePortForProcess (lldb::pid_t pid)
- {
- if (!m_port_map.empty())
- {
- for (auto &pair : m_port_map)
- {
- if (pair.second == pid)
- {
- pair.second = LLDB_INVALID_PROCESS_ID;
- return true;
- }
- }
- }
- return false;
- }
-
- void
- SetPortOffset (uint16_t port_offset)
- {
- m_port_offset = port_offset;
- }
-
- //------------------------------------------------------------------
- /// Specify the program to launch and its arguments.
- ///
- /// @param[in] args
- /// The command line to launch.
- ///
- /// @param[in] argc
- /// The number of elements in the args array of cstring pointers.
- ///
- /// @return
- /// An Error object indicating the success or failure of making
- /// the setting.
- //------------------------------------------------------------------
- lldb_private::Error
- SetLaunchArguments (const char *const args[], int argc);
-
- //------------------------------------------------------------------
- /// Specify the launch flags for the process.
- ///
- /// @param[in] launch_flags
- /// The launch flags to use when launching this process.
- ///
- /// @return
- /// An Error object indicating the success or failure of making
- /// the setting.
- //------------------------------------------------------------------
- lldb_private::Error
- SetLaunchFlags (unsigned int launch_flags);
-
- //------------------------------------------------------------------
- /// Launch a process with the current launch settings.
- ///
- /// This method supports running an lldb-gdbserver or similar
- /// server in a situation where the startup code has been provided
- /// with all the information for a child process to be launched.
- ///
- /// @return
- /// An Error object indicating the success or failure of the
- /// launch.
- //------------------------------------------------------------------
- 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;
+ HandshakeWithClient (Error *error_ptr);
protected:
- lldb::PlatformSP m_platform_sp;
- lldb::thread_t m_async_thread;
- lldb_private::ProcessLaunchInfo m_process_launch_info;
- lldb_private::Error m_process_launch_error;
- std::set<lldb::pid_t> m_spawned_pids;
- lldb_private::Mutex m_spawned_pids_mutex;
- lldb_private::ProcessInstanceInfoList m_proc_infos;
- 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;
+ std::map<StringExtractorGDBRemote::ServerPacketType, PacketHandler> m_packet_handlers;
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);
@@ -255,306 +72,14 @@ protected:
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
- Handle_qLaunchSuccess (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qHostInfo (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_k (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qPlatform_chmod (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qProcessInfo (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qfProcessInfo (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qsProcessInfo (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qC (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qUserName (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qGroupName (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qSpeedTest (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_QEnvironment (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_QLaunchArch (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_QSetDetachOnError (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_QSetWorkingDir (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qGetWorkingDir (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_QStartNoAckMode (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_QSetSTDIN (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_QSetSTDOUT (StringExtractorGDBRemote &packet);
-
- 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);
-
- PacketResult
- Handle_vFile_Close (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_vFile_pRead (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_vFile_pWrite (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_vFile_Size (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_vFile_Mode (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_vFile_Exists (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_vFile_symlink (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_vFile_unlink (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_vFile_Stat (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_vFile_MD5 (StringExtractorGDBRemote &packet);
-
- 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_I (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);
-
- PacketResult
- Handle_D (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qThreadStopInfo (StringExtractorGDBRemote &packet);
-
- PacketResult
- Handle_qWatchpointSupportInfo (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);
-
- static bool
- ReapDebugserverProcess (void *callback_baton,
- lldb::pid_t pid,
- bool exited,
- int signal,
- int status);
-
- bool
- DebuggedProcessReaped (lldb::pid_t pid);
-
- static bool
- ReapDebuggedProcess (void *callback_baton,
- lldb::pid_t pid,
- bool exited,
- int signal,
- int status);
-
- bool
- KillSpawnedProcess (lldb::pid_t pid);
-
- bool
- IsGdbServer ()
- {
- return !m_is_platform;
- }
-
- /// Launch an inferior process from lldb-gdbserver
- lldb_private::Error
- LaunchProcessForDebugging ();
-
- /// 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 ();
-
- bool
- ShouldRedirectInferiorOutputOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const;
-
//------------------------------------------------------------------
// For GDBRemoteCommunicationServer only
//------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServer);
};
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
#endif // liblldb_GDBRemoteCommunicationServer_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
new file mode 100644
index 000000000000..698854e5dfbd
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -0,0 +1,1341 @@
+//===-- GDBRemoteCommunicationServerCommon.cpp ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteCommunicationServerCommon.h"
+
+#include <errno.h>
+
+// C Includes
+// C++ Includes
+#include <cstring>
+#include <chrono>
+
+// Other libraries and framework includes
+#include "llvm/ADT/Triple.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/StreamGDBRemote.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Config.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/StringConvert.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/FileAction.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+
+// Project includes
+#include "ProcessGDBRemoteLog.h"
+#include "Utility/StringExtractorGDBRemote.h"
+
+#ifdef __ANDROID__
+#include "lldb/Host/android/HostInfoAndroid.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+#ifdef __ANDROID__
+ const static uint32_t g_default_packet_timeout_sec = 20; // seconds
+#else
+ const static uint32_t g_default_packet_timeout_sec = 0; // not specified
+#endif
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunicationServerCommon constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name) :
+ GDBRemoteCommunicationServer (comm_name, listener_name),
+ m_spawned_pids (),
+ m_spawned_pids_mutex (Mutex::eMutexTypeRecursive),
+ m_process_launch_info (),
+ m_process_launch_error (),
+ m_proc_infos (),
+ m_proc_infos_index (0),
+ m_thread_suffix_supported (false),
+ m_list_threads_in_stop_reply (false)
+{
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_A,
+ &GDBRemoteCommunicationServerCommon::Handle_A);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironment,
+ &GDBRemoteCommunicationServerCommon::Handle_QEnvironment);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironmentHexEncoded,
+ &GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfProcessInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGroupName,
+ &GDBRemoteCommunicationServerCommon::Handle_qGroupName);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qHostInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qHostInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess,
+ &GDBRemoteCommunicationServerCommon::Handle_qKillSpawnedProcess);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QLaunchArch,
+ &GDBRemoteCommunicationServerCommon::Handle_QLaunchArch);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess,
+ &GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply,
+ &GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qEcho,
+ &GDBRemoteCommunicationServerCommon::Handle_qEcho);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qModuleInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qModuleInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod,
+ &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir,
+ &GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_shell,
+ &GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID,
+ &GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDERR,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDIN,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSpeedTest,
+ &GDBRemoteCommunicationServerCommon::Handle_qSpeedTest);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsProcessInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode,
+ &GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSupported,
+ &GDBRemoteCommunicationServerCommon::Handle_qSupported);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported,
+ &GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qUserName,
+ &GDBRemoteCommunicationServerCommon::Handle_qUserName);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_close,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Close);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_exists,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Exists);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_md5,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_MD5);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_mode,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Mode);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_open,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Open);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pread,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_pRead);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pwrite,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_size,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Size);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_stat,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Stat);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_symlink,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_symlink);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_unlink,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_unlink);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerCommon::~GDBRemoteCommunicationServerCommon()
+{
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qHostInfo (StringExtractorGDBRemote &packet)
+{
+ StreamString response;
+
+ // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
+
+ ArchSpec host_arch(HostInfo::GetArchitecture());
+ const llvm::Triple &host_triple = host_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
+ response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
+
+ const char* distribution_id = host_arch.GetDistributionId ().AsCString ();
+ if (distribution_id)
+ {
+ response.PutCString("distribution_id:");
+ response.PutCStringAsRawHex8(distribution_id);
+ 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)
+ response.Printf ("cputype:%u;", cpu);
+ if (sub != LLDB_INVALID_CPUTYPE)
+ response.Printf ("cpusubtype:%u;", sub);
+
+ if (cpu == ArchSpec::kCore_arm_any)
+ 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
+ if (host_arch.GetMachine() == llvm::Triple::mips64 ||
+ host_arch.GetMachine() == llvm::Triple::mips64el)
+ response.Printf("watchpoint_exceptions_received:before;");
+ else
+ response.Printf("watchpoint_exceptions_received:after;");
+#endif
+
+ switch (lldb::endian::InlHostByteOrder())
+ {
+ case eByteOrderBig: response.PutCString ("endian:big;"); break;
+ case eByteOrderLittle: response.PutCString ("endian:little;"); break;
+ case eByteOrderPDP: response.PutCString ("endian:pdp;"); break;
+ default: response.PutCString ("endian:unknown;"); break;
+ }
+
+ uint32_t major = UINT32_MAX;
+ uint32_t minor = UINT32_MAX;
+ uint32_t update = UINT32_MAX;
+ if (HostInfo::GetOSVersion(major, minor, update))
+ {
+ if (major != UINT32_MAX)
+ {
+ response.Printf("os_version:%u", major);
+ if (minor != UINT32_MAX)
+ {
+ response.Printf(".%u", minor);
+ if (update != UINT32_MAX)
+ response.Printf(".%u", update);
+ }
+ response.PutChar(';');
+ }
+ }
+
+ std::string s;
+ if (HostInfo::GetOSBuildString(s))
+ {
+ response.PutCString ("os_build:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+ if (HostInfo::GetOSKernelDescription(s))
+ {
+ response.PutCString ("os_kernel:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+
+#if defined(__APPLE__)
+
+#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("127.0.0.1");
+ response.PutChar(';');
+#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__) || defined(__arm64__) || defined(__aarch64__)
+
+#else // #if defined(__APPLE__)
+ if (HostInfo::GetHostname(s))
+ {
+ response.PutCString ("hostname:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+#endif // #if defined(__APPLE__)
+
+ if (g_default_packet_timeout_sec > 0)
+ response.Printf ("default_packet_timeout:%u;", g_default_packet_timeout_sec);
+
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
+{
+ // Packet format: "qProcessInfoPID:%i" where %i is the pid
+ packet.SetFilePos (::strlen ("qProcessInfoPID:"));
+ lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID);
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ProcessInstanceInfo proc_info;
+ if (Host::GetProcessInfo (pid, proc_info))
+ {
+ StreamString response;
+ CreateProcessInfoResponse (proc_info, response);
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (1);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)
+{
+ m_proc_infos_index = 0;
+ m_proc_infos.Clear();
+
+ ProcessInstanceInfoMatch match_info;
+ packet.SetFilePos(::strlen ("qfProcessInfo"));
+ if (packet.GetChar() == ':')
+ {
+
+ std::string key;
+ std::string value;
+ while (packet.GetNameColonValue(key, value))
+ {
+ bool success = true;
+ if (key.compare("name") == 0)
+ {
+ StringExtractor extractor;
+ extractor.GetStringRef().swap(value);
+ extractor.GetHexByteString (value);
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false);
+ }
+ else if (key.compare("name_match") == 0)
+ {
+ if (value.compare("equals") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchEquals);
+ }
+ else if (value.compare("starts_with") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchStartsWith);
+ }
+ else if (value.compare("ends_with") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchEndsWith);
+ }
+ else if (value.compare("contains") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchContains);
+ }
+ else if (value.compare("regex") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchRegularExpression);
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ else if (key.compare("pid") == 0)
+ {
+ match_info.GetProcessInfo().SetProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+ }
+ else if (key.compare("parent_pid") == 0)
+ {
+ match_info.GetProcessInfo().SetParentProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+ }
+ else if (key.compare("uid") == 0)
+ {
+ match_info.GetProcessInfo().SetUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("gid") == 0)
+ {
+ match_info.GetProcessInfo().SetGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("euid") == 0)
+ {
+ match_info.GetProcessInfo().SetEffectiveUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("egid") == 0)
+ {
+ match_info.GetProcessInfo().SetEffectiveGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("all_users") == 0)
+ {
+ match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success));
+ }
+ else if (key.compare("triple") == 0)
+ {
+ match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL);
+ }
+ else
+ {
+ success = false;
+ }
+
+ if (!success)
+ return SendErrorResponse (2);
+ }
+ }
+
+ if (Host::FindProcesses (match_info, m_proc_infos))
+ {
+ // We found something, return the first item by calling the get
+ // subsequent process info packet handler...
+ return Handle_qsProcessInfo (packet);
+ }
+ return SendErrorResponse (3);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo (StringExtractorGDBRemote &packet)
+{
+ if (m_proc_infos_index < m_proc_infos.GetSize())
+ {
+ StreamString response;
+ CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response);
+ ++m_proc_infos_index;
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse (4);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qUserName (StringExtractorGDBRemote &packet)
+{
+#if !defined(LLDB_DISABLE_POSIX)
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__);
+
+ // 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 (HostInfo::LookupUserName(uid, name))
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8 (name.c_str());
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ if (log)
+ log->Printf("GDBRemoteCommunicationServerCommon::%s end", __FUNCTION__);
+#endif
+ return SendErrorResponse (5);
+
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::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 (HostInfo::LookupGroupName(gid, name))
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8 (name.c_str());
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+#endif
+ return SendErrorResponse (6);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("qSpeedTest:"));
+
+ std::string key;
+ std::string value;
+ bool success = packet.GetNameColonValue(key, value);
+ if (success && key.compare("response_size") == 0)
+ {
+ uint32_t response_size = StringConvert::ToUInt32(value.c_str(), 0, 0, &success);
+ if (success)
+ {
+ if (response_size == 0)
+ return SendOKResponse();
+ StreamString response;
+ uint32_t bytes_left = response_size;
+ response.PutCString("data:");
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 26)
+ {
+ response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ bytes_left -= 26;
+ }
+ else
+ {
+ response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ bytes_left = 0;
+ }
+ }
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (7);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
+
+ lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+
+ // verify that we know anything about this pid.
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ {
+ // not a pid we know about
+ return SendErrorResponse (10);
+ }
+ }
+
+ // go ahead and attempt to kill the spawned process
+ if (KillSpawnedProcess (pid))
+ return SendOKResponse ();
+ else
+ return SendErrorResponse (11);
+}
+
+bool
+GDBRemoteCommunicationServerCommon::KillSpawnedProcess (lldb::pid_t pid)
+{
+ // make sure we know about this process
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return false;
+ }
+
+ // first try a SIGTERM (standard kill)
+ Host::Kill (pid, SIGTERM);
+
+ // check if that worked
+ for (size_t i=0; i<10; ++i)
+ {
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ {
+ // it is now killed
+ return true;
+ }
+ }
+ usleep (10000);
+ }
+
+ // check one more time after the final usleep
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+
+ // the launched process still lives. Now try killing it again,
+ // this time with an unblockable signal.
+ Host::Kill (pid, SIGKILL);
+
+ for (size_t i=0; i<10; ++i)
+ {
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ {
+ // it is now killed
+ return true;
+ }
+ }
+ usleep (10000);
+ }
+
+ // check one more time after the final usleep
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+
+ // no luck - the process still lives
+ return false;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Open (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:open:"));
+ std::string path;
+ packet.GetHexByteStringTerminatedBy(path,',');
+ if (!path.empty())
+ {
+ if (packet.GetChar() == ',')
+ {
+ uint32_t flags = File::ConvertOpenOptionsForPOSIXOpen(
+ packet.GetHexMaxU32(false, 0));
+ if (packet.GetChar() == ',')
+ {
+ mode_t mode = packet.GetHexMaxU32(false, 0600);
+ Error error;
+ const FileSpec path_spec{path, true};
+ int fd = ::open(path_spec.GetCString(), flags, mode);
+ const int save_errno = fd == -1 ? errno : 0;
+ StreamString response;
+ response.PutChar('F');
+ response.Printf("%i", fd);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ }
+ return SendErrorResponse(18);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Close (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:close:"));
+ int fd = packet.GetS32(-1);
+ Error error;
+ int err = -1;
+ int save_errno = 0;
+ if (fd >= 0)
+ {
+ err = close(fd);
+ save_errno = err == -1 ? errno : 0;
+ }
+ else
+ {
+ save_errno = EINVAL;
+ }
+ StreamString response;
+ response.PutChar('F');
+ response.Printf("%i", err);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_pRead (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+ // Not implemented on Windows
+ return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pRead() unimplemented");
+#else
+ StreamGDBRemote response;
+ packet.SetFilePos(::strlen("vFile:pread:"));
+ int fd = packet.GetS32(-1);
+ if (packet.GetChar() == ',')
+ {
+ uint64_t count = packet.GetU64(UINT64_MAX);
+ if (packet.GetChar() == ',')
+ {
+ uint64_t offset = packet.GetU64(UINT32_MAX);
+ if (count == UINT64_MAX)
+ {
+ response.Printf("F-1:%i", EINVAL);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+
+ std::string buffer(count, 0);
+ const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
+ const int save_errno = bytes_read == -1 ? errno : 0;
+ response.PutChar('F');
+ response.Printf("%zi", bytes_read);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ else
+ {
+ response.PutChar(';');
+ response.PutEscapedBytes(&buffer[0], bytes_read);
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse(21);
+
+#endif
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+ return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite() unimplemented");
+#else
+ packet.SetFilePos(::strlen("vFile:pwrite:"));
+
+ StreamGDBRemote response;
+ response.PutChar('F');
+
+ int fd = packet.GetU32(UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ off_t offset = packet.GetU64(UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ std::string buffer;
+ if (packet.GetEscapedBinaryData(buffer))
+ {
+ const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
+ const int save_errno = bytes_written == -1 ? errno : 0;
+ response.Printf("%zi", bytes_written);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ }
+ else
+ {
+ response.Printf ("-1,%i", EINVAL);
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse(27);
+#endif
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Size (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:size:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
+ {
+ lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path.c_str(), false));
+ StreamString response;
+ response.PutChar('F');
+ response.PutHex64(retcode);
+ if (retcode == UINT64_MAX)
+ {
+ response.PutChar(',');
+ response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(22);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Mode (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:mode:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
+ {
+ Error error;
+ const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error);
+ StreamString response;
+ response.Printf("F%u", mode);
+ if (mode == 0 || error.Fail())
+ response.Printf(",%i", (int)error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(23);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Exists (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:exists:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
+ {
+ bool retcode = FileSystem::GetFileExists(FileSpec(path.c_str(), false));
+ StreamString response;
+ response.PutChar('F');
+ response.PutChar(',');
+ if (retcode)
+ response.PutChar('1');
+ else
+ response.PutChar('0');
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(24);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_symlink (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:symlink:"));
+ std::string dst, src;
+ packet.GetHexByteStringTerminatedBy(dst, ',');
+ packet.GetChar(); // Skip ',' char
+ packet.GetHexByteString(src);
+ Error error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false});
+ StreamString response;
+ response.Printf("F%u,%u", error.GetError(), error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_unlink (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:unlink:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = FileSystem::Unlink(FileSpec{path, true});
+ StreamString response;
+ response.Printf("F%u,%u", error.GetError(), error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_shell:"));
+ std::string path;
+ std::string working_dir;
+ packet.GetHexByteStringTerminatedBy(path,',');
+ if (!path.empty())
+ {
+ if (packet.GetChar() == ',')
+ {
+ // FIXME: add timeout to qPlatform_shell packet
+ // uint32_t timeout = packet.GetHexMaxU32(false, 32);
+ uint32_t timeout = 10;
+ if (packet.GetChar() == ',')
+ packet.GetHexByteString(working_dir);
+ int status, signo;
+ std::string output;
+ Error err = Host::RunShellCommand(path.c_str(),
+ FileSpec{working_dir, true},
+ &status, &signo, &output, timeout);
+ StreamGDBRemote response;
+ if (err.Fail())
+ {
+ response.PutCString("F,");
+ response.PutHex32(UINT32_MAX);
+ }
+ else
+ {
+ response.PutCString("F,");
+ response.PutHex32(status);
+ response.PutChar(',');
+ response.PutHex32(signo);
+ response.PutChar(',');
+ response.PutEscapedBytes(output.c_str(), output.size());
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse(24);
+}
+
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
+{
+ return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_Stat() unimplemented");
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:MD5:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
+ {
+ uint64_t a,b;
+ StreamGDBRemote response;
+ if (!FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b))
+ {
+ response.PutCString("F,");
+ response.PutCString("x");
+ }
+ else
+ {
+ response.PutCString("F,");
+ response.PutHex64(a);
+ response.PutHex64(b);
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(25);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_mkdir:"));
+ mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = FileSystem::MakeDirectory(FileSpec{path, false}, mode);
+
+ StreamGDBRemote response;
+ response.Printf("F%u", error.GetError());
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(20);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_chmod:"));
+
+ mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = FileSystem::SetFilePermissions(FileSpec{path, true}, mode);
+
+ StreamGDBRemote response;
+ response.Printf("F%u", error.GetError());
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(19);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::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+");
+ response.PutCString (";qEcho+");
+#if defined(__linux__)
+ response.PutCString (";qXfer:auxv:read+");
+#endif
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet)
+{
+ m_thread_suffix_supported = true;
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet)
+{
+ m_list_threads_in_stop_reply = true;
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::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 ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)
+{
+ // Send response first before changing m_send_acks to we ack this packet
+ PacketResult packet_result = SendOKResponse ();
+ m_send_acks = false;
+ return packet_result;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDIN:"));
+ FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDIN_FILENO, FileSpec{path, false}, read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (15);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDOUT:"));
+ FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDOUT_FILENO, FileSpec{path, false}, read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (16);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDERR:"));
+ FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDERR_FILENO, FileSpec{path, false}, read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (17);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
+{
+ if (m_process_launch_error.Success())
+ return SendOKResponse();
+ StreamString response;
+ response.PutChar('E');
+ response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QEnvironment (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QEnvironment:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (12);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("QEnvironmentHexEncoded:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ std::string str;
+ packet.GetHexByteString(str);
+ m_process_launch_info.GetEnvironmentEntries().AppendArgument(str.c_str());
+ return SendOKResponse();
+ }
+ return SendErrorResponse(12);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QLaunchArch (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QLaunchArch:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ const char* arch_triple = packet.Peek();
+ ArchSpec arch_spec(arch_triple,NULL);
+ m_process_launch_info.SetArchitecture(arch_spec);
+ return SendOKResponse();
+ }
+ return SendErrorResponse(13);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_A (StringExtractorGDBRemote &packet)
+{
+ // The 'A' packet is the most over designed packet ever here with
+ // redundant argument indexes, redundant argument lengths and needed hex
+ // encoded argument string values. Really all that is needed is a comma
+ // 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)
+ {
+ // Decode the decimal argument string length. This length is the
+ // number of hex nibbles in the argument string value.
+ const uint32_t arg_len = packet.GetU32(UINT32_MAX);
+ if (arg_len == UINT32_MAX)
+ success = false;
+ else
+ {
+ // Make sure the argument hex string length is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // 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)
+ success = false;
+ else
+ {
+ // Make sure the argument index is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // Decode the argument string value from hex bytes
+ // back into a UTF8 string and make sure the length
+ // matches the one supplied in the packet
+ std::string arg;
+ if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2))
+ success = false;
+ else
+ {
+ // If there are any bytes left
+ if (packet.GetBytesLeft())
+ {
+ if (packet.GetChar() != ',')
+ success = false;
+ }
+
+ if (success)
+ {
+ 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 ("LLGSPacketHandler::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ());
+ ++actual_arg_index;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success)
+ {
+ 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("LLGSPacketHandler::%s failed to launch exe: %s",
+ __FUNCTION__,
+ m_process_launch_error.AsCString());
+
+ }
+ }
+ return SendErrorResponse (8);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qEcho (StringExtractorGDBRemote &packet)
+{
+ // Just echo back the exact same packet for qEcho...
+ return SendPacketNoLock(packet.GetStringRef().c_str(), packet.GetStringRef().size());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qModuleInfo (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("qModuleInfo:"));
+
+ std::string module_path;
+ packet.GetHexByteStringTerminatedBy(module_path, ';');
+ if (module_path.empty())
+ return SendErrorResponse (1);
+
+ if (packet.GetChar() != ';')
+ return SendErrorResponse (2);
+
+ std::string triple;
+ packet.GetHexByteString(triple);
+ ArchSpec arch(triple.c_str());
+
+ const FileSpec req_module_path_spec(module_path.c_str(), true);
+ const FileSpec module_path_spec = FindModuleFile(req_module_path_spec.GetPath(), arch);
+ const ModuleSpec module_spec(module_path_spec, arch);
+
+ ModuleSpecList module_specs;
+ if (!ObjectFile::GetModuleSpecifications(module_path_spec, 0, 0, module_specs))
+ return SendErrorResponse (3);
+
+ ModuleSpec matched_module_spec;
+ if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
+ return SendErrorResponse (4);
+
+ const auto file_offset = matched_module_spec.GetObjectOffset();
+ const auto file_size = matched_module_spec.GetObjectSize();
+ const auto uuid_str = matched_module_spec.GetUUID().GetAsString("");
+
+ StreamGDBRemote response;
+
+ if (uuid_str.empty())
+ {
+ std::string md5_hash;
+ if (!FileSystem::CalculateMD5AsString(matched_module_spec.GetFileSpec(), file_offset, file_size, md5_hash))
+ return SendErrorResponse (5);
+ response.PutCString ("md5:");
+ response.PutCStringAsRawHex8(md5_hash.c_str());
+ }
+ else{
+ response.PutCString ("uuid:");
+ response.PutCStringAsRawHex8(uuid_str.c_str());
+ }
+ response.PutChar(';');
+
+ const auto &module_arch = matched_module_spec.GetArchitecture();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8( module_arch.GetTriple().getTriple().c_str());
+ response.PutChar(';');
+
+ response.PutCString("file_path:");
+ response.PutCStringAsRawHex8(module_path_spec.GetCString());
+ response.PutChar(';');
+ response.PutCString("file_offset:");
+ response.PutHex64(file_offset);
+ response.PutChar(';');
+ response.PutCString("file_size:");
+ response.PutHex64(file_size);
+ response.PutChar(';');
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+void
+GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info,
+ StreamString &response)
+{
+ response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;",
+ proc_info.GetProcessID(),
+ proc_info.GetParentProcessID(),
+ proc_info.GetUserID(),
+ proc_info.GetGroupID(),
+ proc_info.GetEffectiveUserID(),
+ proc_info.GetEffectiveGroupID());
+ response.PutCString ("name:");
+ response.PutCStringAsRawHex8(proc_info.GetExecutableFile().GetCString());
+ response.PutChar(';');
+ const ArchSpec &proc_arch = proc_info.GetArchitecture();
+ if (proc_arch.IsValid())
+ {
+ const llvm::Triple &proc_triple = proc_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
+ response.PutChar(';');
+ }
+}
+
+void
+GDBRemoteCommunicationServerCommon::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.PutCString("triple:");
+ response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
+ response.PutChar(';');
+#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;");
+ }
+}
+
+FileSpec
+GDBRemoteCommunicationServerCommon::FindModuleFile(const std::string& module_path,
+ const ArchSpec& arch)
+{
+#ifdef __ANDROID__
+ return HostInfoAndroid::ResolveLibraryPath(module_path, arch);
+#else
+ return FileSpec(module_path.c_str(), true);
+#endif
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
new file mode 100644
index 000000000000..62b129bb18b9
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
@@ -0,0 +1,216 @@
+//===-- GDBRemoteCommunicationServerCommon.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_GDBRemoteCommunicationServerCommon_h_
+#define liblldb_GDBRemoteCommunicationServerCommon_h_
+
+// C Includes
+// C++ Includes
+#include <set>
+
+// Other libraries and framework includes
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+
+// Project includes
+#include "GDBRemoteCommunicationServer.h"
+#include "GDBRemoteCommunicationServerCommon.h"
+
+class StringExtractorGDBRemote;
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunicationServerCommon :
+ public GDBRemoteCommunicationServer
+{
+public:
+ GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name);
+
+ virtual
+ ~GDBRemoteCommunicationServerCommon();
+
+protected:
+ std::set<lldb::pid_t> m_spawned_pids;
+ Mutex m_spawned_pids_mutex;
+ ProcessLaunchInfo m_process_launch_info;
+ Error m_process_launch_error;
+ ProcessInstanceInfoList m_proc_infos;
+ uint32_t m_proc_infos_index;
+ bool m_thread_suffix_supported;
+ bool m_list_threads_in_stop_reply;
+
+ PacketResult
+ Handle_A (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qHostInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qfProcessInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qsProcessInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qUserName (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qGroupName (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qSpeedTest (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Open (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Close (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_pRead (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_pWrite (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Size (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Mode (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Exists (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_symlink (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_unlink (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Stat (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_MD5 (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qEcho (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qModuleInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qPlatform_shell (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qPlatform_chmod (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qSupported (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetDetachOnError (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QStartNoAckMode (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetSTDIN (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetSTDOUT (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetSTDERR (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qLaunchSuccess (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QEnvironment (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QEnvironmentHexEncoded (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QLaunchArch (StringExtractorGDBRemote &packet);
+
+ bool
+ KillSpawnedProcess (lldb::pid_t pid);
+
+ static void
+ CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info,
+ StreamString &response);
+
+ static void
+ CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info,
+ StreamString &response);
+
+ template <typename T>
+ void
+ RegisterMemberFunctionHandler (StringExtractorGDBRemote::ServerPacketType packet_type,
+ PacketResult (T::*handler) (StringExtractorGDBRemote& packet))
+ {
+ RegisterPacketHandler(packet_type,
+ [this, handler] (StringExtractorGDBRemote packet,
+ Error &error,
+ bool &interrupt,
+ bool &quit)
+ {
+ return (static_cast<T*>(this)->*handler) (packet);
+ });
+ }
+
+ bool
+ GetThreadSuffixSupported () override
+ {
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Launch a process with the current launch settings.
+ ///
+ /// This method supports running an lldb-gdbserver or similar
+ /// server in a situation where the startup code has been provided
+ /// with all the information for a child process to be launched.
+ ///
+ /// @return
+ /// An Error object indicating the success or failure of the
+ /// launch.
+ //------------------------------------------------------------------
+ virtual Error
+ LaunchProcess () = 0;
+
+ virtual FileSpec
+ FindModuleFile (const std::string& module_path, const ArchSpec& arch);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_GDBRemoteCommunicationServerCommon_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
new file mode 100644
index 000000000000..e8955ddbd6e4
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -0,0 +1,2787 @@
+//===-- GDBRemoteCommunicationServerLLGS.cpp --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <errno.h>
+
+#include "lldb/Host/Config.h"
+
+#include "GDBRemoteCommunicationServerLLGS.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/DataBuffer.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/ConnectionFileDescriptor.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/StringConvert.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/FileAction.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "Utility/UriParser.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace llvm;
+
+//----------------------------------------------------------------------
+// GDBRemote Errors
+//----------------------------------------------------------------------
+
+namespace
+{
+ enum GDBRemoteServerError
+ {
+ // Set to the first unused error number in literal form below
+ eErrorFirst = 29,
+ eErrorNoProcess = eErrorFirst,
+ eErrorResume,
+ eErrorExitStatus
+ };
+}
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunicationServerLLGS constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS(
+ const lldb::PlatformSP& platform_sp) :
+ GDBRemoteCommunicationServerCommon ("gdb-remote.server", "gdb-remote.server.rx_packet"),
+ m_platform_sp (platform_sp),
+ m_async_thread (LLDB_INVALID_HOST_THREAD),
+ 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_stdio_communication ("process.stdio"),
+ m_inferior_prev_state (StateType::eStateInvalid),
+ m_active_auxv_buffer_sp (),
+ m_saved_registers_mutex (),
+ m_saved_registers_map (),
+ m_next_saved_registers_id (1)
+{
+ assert(platform_sp);
+ RegisterPacketHandlers();
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerLLGS::~GDBRemoteCommunicationServerLLGS()
+{
+ Mutex::Locker locker (m_debugged_process_mutex);
+
+ if (m_debugged_process_sp)
+ {
+ m_debugged_process_sp->Terminate ();
+ m_debugged_process_sp.reset ();
+ }
+}
+
+void
+GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers()
+{
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_C,
+ &GDBRemoteCommunicationServerLLGS::Handle_C);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_c,
+ &GDBRemoteCommunicationServerLLGS::Handle_c);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_D,
+ &GDBRemoteCommunicationServerLLGS::Handle_D);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_H,
+ &GDBRemoteCommunicationServerLLGS::Handle_H);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_I,
+ &GDBRemoteCommunicationServerLLGS::Handle_I);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
+ &GDBRemoteCommunicationServerLLGS::Handle_interrupt);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_m,
+ &GDBRemoteCommunicationServerLLGS::Handle_m);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M,
+ &GDBRemoteCommunicationServerLLGS::Handle_M);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p,
+ &GDBRemoteCommunicationServerLLGS::Handle_p);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P,
+ &GDBRemoteCommunicationServerLLGS::Handle_P);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC,
+ &GDBRemoteCommunicationServerLLGS::Handle_qC);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfThreadInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qFileLoadAddress,
+ &GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
+ &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported,
+ &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qRegisterInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState,
+ &GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState,
+ &GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR,
+ &GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
+ &GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsThreadInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read,
+ &GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_s,
+ &GDBRemoteCommunicationServerLLGS::Handle_s);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_stop_reason,
+ &GDBRemoteCommunicationServerLLGS::Handle_stop_reason); // ?
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vAttach,
+ &GDBRemoteCommunicationServerLLGS::Handle_vAttach);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vCont,
+ &GDBRemoteCommunicationServerLLGS::Handle_vCont);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vCont_actions,
+ &GDBRemoteCommunicationServerLLGS::Handle_vCont_actions);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_Z,
+ &GDBRemoteCommunicationServerLLGS::Handle_Z);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z,
+ &GDBRemoteCommunicationServerLLGS::Handle_z);
+
+ RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k,
+ [this](StringExtractorGDBRemote packet,
+ Error &error,
+ bool &interrupt,
+ bool &quit)
+ {
+ quit = true;
+ return this->Handle_k (packet);
+ });
+}
+
+Error
+GDBRemoteCommunicationServerLLGS::SetLaunchArguments (const char *const args[], int argc)
+{
+ if ((argc < 1) || !args || !args[0] || !args[0][0])
+ return Error ("%s: no process command line specified to launch", __FUNCTION__);
+
+ m_process_launch_info.SetArguments (const_cast<const char**> (args), true);
+ return Error ();
+}
+
+Error
+GDBRemoteCommunicationServerLLGS::SetLaunchFlags (unsigned int launch_flags)
+{
+ m_process_launch_info.GetFlags ().Set (launch_flags);
+ return Error ();
+}
+
+Error
+GDBRemoteCommunicationServerLLGS::LaunchProcess ()
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
+ return Error ("%s: no process command line specified to launch", __FUNCTION__);
+
+ 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;
+ }
+
+ // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol
+ // as needed.
+ // llgs local-process debugging may specify PTY paths, which will make these
+ // file actions non-null
+ // process launch -i/e/o will also make these file actions non-null
+ // nullptr means that the traffic is expected to flow over gdb-remote protocol
+ if (
+ m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr ||
+ m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr ||
+ m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr
+ )
+ {
+ // nullptr means it's not redirected to file or pty (in case of LLGS local)
+ // at least one of stdio will be transferred pty<->gdb-remote
+ // we need to give the pty master handle to this object to read and/or write
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " setting up stdout/stderr redirection via $O gdb-remote commands", __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // Setup stdout/stderr mapping from inferior to $O
+ auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor ();
+ if (terminal_fd >= 0)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd);
+ error = SetSTDIOFileDescriptor (terminal_fd);
+ if (error.Fail ())
+ return error;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " skipping stdout/stderr redirection via $O: inferior will communicate over client-provided file descriptors", __FUNCTION__, m_debugged_process_sp->GetID ());
+ }
+
+ 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);
+ }
+
+ return error;
+}
+
+Error
+GDBRemoteCommunicationServerLLGS::AttachToProcess (lldb::pid_t pid)
+{
+ Error error;
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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 ("ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd);
+ error = SetSTDIOFileDescriptor (terminal_fd);
+ if (error.Fail ())
+ return error;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%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
+GDBRemoteCommunicationServerLLGS::InitializeDelegate (NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid %" PRIu64 ", current state: %s",
+ __FUNCTION__,
+ process->GetID (),
+ StateAsCString (process->GetState ()));
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::SendWResponse (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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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:
+ 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);
+ }
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+
+ // 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 ("GDBRemoteCommunicationServerLLGS::%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;
+ std::string description;
+ if (!thread_sp->GetStopReason (tid_stop_info, description))
+ return SendErrorResponse (52);
+
+ // FIXME implement register handling for exec'd inferiors.
+ // if (tid_stop_info.reason == eStopReasonExec)
+ // {
+ // 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 ("GDBRemoteCommunicationServerLLGS::%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);
+ }
+
+ // 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 std::string thread_name = thread_sp->GetName ();
+ if (!thread_name.empty ())
+ {
+ size_t thread_name_len = thread_name.length ();
+
+ if (::strcspn (thread_name.c_str (), "$#+-;:") == thread_name_len)
+ {
+ response.PutCString ("name:");
+ response.PutCString (thread_name.c_str ());
+ }
+ else
+ {
+ // The thread name contains special chars, send as hex bytes.
+ response.PutCString ("hexname:");
+ response.PutCStringAsRawHex8 (thread_name.c_str ());
+ }
+ response.PutChar (';');
+ }
+
+ // 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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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 ())
+ {
+ response.Printf ("%.02x:", *reg_num_p);
+ WriteRegisterValueInHexFixedWidth(response, reg_ctx_sp, *reg_info_p, &reg_value);
+ response.PutChar (';');
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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 ());
+
+ }
+ }
+ }
+ }
+ }
+
+ const char* reason_str = nullptr;
+ switch (tid_stop_info.reason)
+ {
+ case eStopReasonTrace:
+ reason_str = "trace";
+ break;
+ case eStopReasonBreakpoint:
+ reason_str = "breakpoint";
+ break;
+ case eStopReasonWatchpoint:
+ reason_str = "watchpoint";
+ break;
+ case eStopReasonSignal:
+ reason_str = "signal";
+ break;
+ case eStopReasonException:
+ reason_str = "exception";
+ break;
+ case eStopReasonExec:
+ reason_str = "exec";
+ break;
+ case eStopReasonInstrumentation:
+ case eStopReasonInvalid:
+ case eStopReasonPlanComplete:
+ case eStopReasonThreadExiting:
+ case eStopReasonNone:
+ break;
+ }
+ if (reason_str != nullptr)
+ {
+ response.Printf ("reason:%s;", reason_str);
+ }
+
+ if (!description.empty())
+ {
+ // Description may contains special chars, send as hex bytes.
+ response.PutCString ("description:");
+ response.PutCStringAsRawHex8 (description.c_str ());
+ response.PutChar (';');
+ }
+ 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
+GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited (NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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);
+ if (m_spawned_pids.erase (process->GetID ()) < 1)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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
+GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped (NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ());
+ }
+ break;
+ }
+}
+
+void
+GDBRemoteCommunicationServerLLGS::ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state)
+{
+ assert (process && "process cannot be NULL");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid %" PRIu64 ", state: %s",
+ __FUNCTION__,
+ process->GetID (),
+ StateAsCString (state));
+ }
+
+ // Make sure we get all of the pending stdout/stderr from the inferior
+ // and send it to the lldb host before we send the state change
+ // notification
+ m_stdio_communication.SynchronizeWithReadThread();
+
+ switch (state)
+ {
+ case StateType::eStateExited:
+ HandleInferiorState_Exited (process);
+ break;
+
+ case StateType::eStateStopped:
+ HandleInferiorState_Stopped (process);
+ break;
+
+ default:
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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
+GDBRemoteCommunicationServerLLGS::DidExec (NativeProcessProtocol *process)
+{
+ ClearProcessSpecificData ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::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 ());
+}
+
+Error
+GDBRemoteCommunicationServerLLGS::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.SetCloseOnEOF (false);
+ 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;
+ }
+
+ // llgs local-process debugging may specify PTY paths, which will make these
+ // file actions non-null
+ // process launch -e/o will also make these file actions non-null
+ // nullptr means that the traffic is expected to flow over gdb-remote protocol
+ if (
+ m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr ||
+ m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr
+ )
+ {
+ // output from the process must be forwarded over gdb-remote
+ // create a thread to read the handle and send the data
+ m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this);
+ m_stdio_communication.StartReadThread();
+ }
+
+ return error;
+}
+
+void
+GDBRemoteCommunicationServerLLGS::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len)
+{
+ GDBRemoteCommunicationServerLLGS *server = reinterpret_cast<GDBRemoteCommunicationServerLLGS*> (baton);
+ static_cast<void> (server->SendONotification (static_cast<const char *>(src), src_len));
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo (StringExtractorGDBRemote &packet)
+{
+ // 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);
+
+ lldb::pid_t pid = m_debugged_process_sp->GetID ();
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse (1);
+
+ ProcessInstanceInfo proc_info;
+ if (!Host::GetProcessInfo (pid, proc_info))
+ return SendErrorResponse (1);
+
+ StreamString response;
+ CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qC (StringExtractorGDBRemote &packet)
+{
+ // 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);
+
+ StreamString response;
+ response.Printf ("QC%" PRIx64, thread_sp->GetID ());
+
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+bool
+GDBRemoteCommunicationServerLLGS::DebuggedProcessReaped (lldb::pid_t pid)
+{
+ // reap a process that we were debugging (but not debugserver)
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ return m_spawned_pids.erase(pid) > 0;
+}
+
+bool
+GDBRemoteCommunicationServerLLGS::ReapDebuggedProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal, // Zero for no signal
+ int status) // Exit value of process if signal is zero
+{
+ GDBRemoteCommunicationServerLLGS *server = (GDBRemoteCommunicationServerLLGS *)callback_baton;
+ server->DebuggedProcessReaped (pid);
+ return true;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_k (StringExtractorGDBRemote &packet)
+{
+ // shutdown all spawned processes
+ std::set<lldb::pid_t> spawned_pids_copy;
+
+ // copy pids
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ());
+ }
+
+ // nuke the spawned processes
+ for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it)
+ {
+ lldb::pid_t spawned_pid = *it;
+ if (!KillSpawnedProcess (spawned_pid))
+ {
+ fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid);
+ }
+ }
+
+ FlushInferiorOutput ();
+
+ // No OK response for kill packet.
+ // return SendOKResponse ();
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetDisableASLR:"));
+ if (packet.GetU32(0))
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+ else
+ m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos (::strlen ("QSetWorkingDir:"));
+ std::string path;
+ packet.GetHexByteString (path);
+ m_process_launch_info.SetWorkingDirectory(FileSpec{path, true});
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()};
+ if (working_dir)
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8(working_dir.GetCString());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+
+ return SendErrorResponse(14);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_C (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
+
+ // Ensure we have a native process.
+ if (!m_debugged_process_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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}");
+ }
+
+ 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).
+ 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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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
+GDBRemoteCommunicationServerLLGS::Handle_c (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
+
+ packet.SetFilePos (packet.GetFilePos() + ::strlen ("c"));
+
+ // For now just support all continue.
+ const bool has_continue_address = (packet.GetBytesLeft () > 0);
+ if (has_continue_address)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__);
+ return SendErrorResponse (0x36);
+ }
+
+ // Build the ResumeActionList
+ ResumeActionList actions (StateType::eStateRunning, 0);
+
+ Error error = m_debugged_process_sp->Resume (actions);
+ if (error.Fail ())
+ {
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s c failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ }
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from continue.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vCont_actions (StringExtractorGDBRemote &packet)
+{
+ StreamString response;
+ response.Printf("vCont;c;C;s;S");
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vCont (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s handling vCont packet", __FUNCTION__);
+
+ packet.SetFilePos (::strlen ("vCont"));
+
+ if (packet.GetBytesLeft() == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s missing action from vCont package", __FUNCTION__);
+ return SendIllFormedResponse (packet, "Missing action from vCont package");
+ }
+
+ // Check if this is all continue (no options or ";c").
+ if (::strcmp (packet.Peek (), ";c") == 0)
+ {
+ // Move past the ';', then do a simple 'c'.
+ packet.SetFilePos (packet.GetFilePos () + 1);
+ return Handle_c (packet);
+ }
+ 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 ("GDBRemoteCommunicationServerLLGS::%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);
+ }
+
+ Error error = m_debugged_process_sp->Resume (thread_actions);
+ if (error.Fail ())
+ {
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s vCont failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ }
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from vCont.
+ return PacketResult::Success;
+}
+
+void
+GDBRemoteCommunicationServerLLGS::SetCurrentThreadID (lldb::tid_t tid)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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
+GDBRemoteCommunicationServerLLGS::SetContinueThreadID (lldb::tid_t tid)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s setting continue thread id to %" PRIu64, __FUNCTION__, tid);
+
+ m_continue_tid = tid;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_stop_reason (StringExtractorGDBRemote &packet)
+{
+ // Handle the $? gdbremote command.
+
+ // If no process, indicate error
+ if (!m_debugged_process_sp)
+ return SendErrorResponse (02);
+
+ return SendStopReasonForState (m_debugged_process_sp->GetState (), true);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::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 ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", current state reporting not handled: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ StateAsCString (process_state));
+ }
+ break;
+ }
+
+ return SendErrorResponse (0);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo (StringExtractorGDBRemote &packet)
+{
+ // 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->GetUserRegisterCount ())
+ 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
+GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo (StringExtractorGDBRemote &packet)
+{
+ 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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%s() finished thread iteration", __FUNCTION__);
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo (StringExtractorGDBRemote &packet)
+{
+ // FIXME for now we return the full thread list in the initial packet and always do nothing here.
+ return SendPacketNoLock ("l", 1);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_p (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // 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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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->GetUserRegisterCount ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ());
+ return SendErrorResponse (0x15);
+ }
+
+ const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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
+GDBRemoteCommunicationServerLLGS::Handle_P (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // 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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%s failed to retrieve inferior architecture", __FUNCTION__);
+ return SendErrorResponse (0x49);
+ }
+
+ // Parse out the value.
+ uint8_t reg_bytes[32]; // big enough to support up to 256 bit ymmN register
+ size_t reg_size = packet.GetHexBytesAvail (reg_bytes, sizeof(reg_bytes));
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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->GetUserRegisterCount ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ());
+ return SendErrorResponse (0x47);
+ }
+
+ if (reg_size != reg_info->byte_size)
+ {
+ return SendIllFormedResponse (packet, "P packet register size is incorrect");
+ }
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ RegisterValue reg_value (reg_bytes, reg_size, process_arch.GetByteOrder ());
+ Error error = reg_context_sp->WriteRegister (reg_info, reg_value);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, write of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ());
+ return SendErrorResponse (0x32);
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_H (StringExtractorGDBRemote &packet)
+{
+ 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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_I (StringExtractorGDBRemote &packet)
+{
+ 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 ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ packet.SetFilePos (::strlen("I"));
+ char tmp[4096];
+ for (;;)
+ {
+ size_t read = packet.GetHexBytesAvail(tmp, sizeof(tmp));
+ if (read == 0)
+ {
+ break;
+ }
+ // write directly to stdin *this might block if stdin buffer is full*
+ // TODO: enqueue this block in circular buffer and send window size to remote host
+ ConnectionStatus status;
+ Error error;
+ m_stdio_communication.Write(tmp, read, status, &error);
+ if (error.Fail())
+ {
+ return SendErrorResponse (0x15);
+ }
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_interrupt (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | 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 ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Interrupt the process.
+ Error error = m_debugged_process_sp->Interrupt ();
+ if (error.Fail ())
+ {
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ }
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s stopped process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from stop all.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_m (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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.
+ size_t bytes_read = 0;
+ Error error = m_debugged_process_sp->ReadMemoryWithoutTrap(read_addr, &buf[0], byte_count, bytes_read);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, byte_count);
+ return SendErrorResponse (0x08);
+ }
+
+ StreamGDBRemote response;
+ for (size_t i = 0; i < bytes_read; ++i)
+ response.PutHex8(buf[i]);
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_M (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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 = packet.GetHexBytes(&buf[0], byte_count, 0);
+ if (convert_count != byte_count)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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.
+ size_t bytes_written = 0;
+ Error error = m_debugged_process_sp->WriteMemory (write_addr, &buf[0], byte_count, bytes_written);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": wrote 0 of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count);
+ return SendErrorResponse (0x09);
+ }
+
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // 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 ("GDBRemoteCommunicationServerLLGS::%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();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_Z (StringExtractorGDBRemote &packet)
+{
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out software or hardware breakpoint or watchpoint 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 GDBStoppointType stoppoint_type =
+ GDBStoppointType(packet.GetS32 (eStoppointInvalid));
+ switch (stoppoint_type)
+ {
+ case eBreakpointSoftware:
+ want_hardware = false; want_breakpoint = true; break;
+ case eBreakpointHardware:
+ want_hardware = true; want_breakpoint = true; break;
+ case eWatchpointWrite:
+ want_hardware = true; want_breakpoint = false; break;
+ case eWatchpointRead:
+ want_hardware = true; want_breakpoint = false; break;
+ case eWatchpointReadWrite:
+ want_hardware = true; want_breakpoint = false; break;
+ case eStoppointInvalid:
+ 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 stoppoint type");
+
+ // Parse out the stoppoint address.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short Z packet, missing address");
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address");
+
+ // Parse out the stoppoint size (i.e. size hint for opcode size).
+ const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (size == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse size argument");
+
+ if (want_breakpoint)
+ {
+ // Try to set the breakpoint.
+ const Error error = m_debugged_process_sp->SetBreakpoint (addr, size, want_hardware);
+ if (error.Success ())
+ return SendOKResponse ();
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
+ " failed to set breakpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+ else
+ {
+ uint32_t watch_flags =
+ stoppoint_type == eWatchpointWrite
+ ? 0x1 // Write
+ : 0x3; // ReadWrite
+
+ // Try to set the watchpoint.
+ const Error error = m_debugged_process_sp->SetWatchpoint (
+ addr, size, watch_flags, want_hardware);
+ if (error.Success ())
+ return SendOKResponse ();
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
+ " failed to set watchpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_z (StringExtractorGDBRemote &packet)
+{
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out software or hardware breakpoint or watchpoint 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 GDBStoppointType stoppoint_type =
+ GDBStoppointType(packet.GetS32 (eStoppointInvalid));
+ switch (stoppoint_type)
+ {
+ case eBreakpointHardware: want_breakpoint = true; break;
+ case eBreakpointSoftware: want_breakpoint = true; break;
+ case eWatchpointWrite: want_breakpoint = false; break;
+ case eWatchpointRead: want_breakpoint = false; break;
+ case eWatchpointReadWrite: 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 stoppoint type");
+
+ // Parse out the stoppoint address.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short z packet, missing address");
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address");
+
+ /*
+ // Parse out the stoppoint size (i.e. size hint for opcode size).
+ const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (size == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse(packet, "Malformed z packet, failed to parse size argument");
+ */
+
+ if (want_breakpoint)
+ {
+ // Try to clear the breakpoint.
+ const Error error = m_debugged_process_sp->RemoveBreakpoint (addr);
+ if (error.Success ())
+ return SendOKResponse ();
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
+ " failed to remove breakpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+ else
+ {
+ // Try to clear the watchpoint.
+ const Error error = m_debugged_process_sp->RemoveWatchpoint (addr);
+ if (error.Success ())
+ return SendOKResponse ();
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
+ " failed to remove watchpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_s (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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.
+ ResumeAction action = { tid, eStateStepping, 0 };
+
+ // Setup the actions list.
+ 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 ("GDBRemoteCommunicationServerLLGS::%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;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet)
+{
+ // *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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // 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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // 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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to restore all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x77);
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vAttach (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // 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 ("GDBRemoteCommunicationServerLLGS::%s attempting to attach to pid %" PRIu64, __FUNCTION__, pid);
+
+ Error error = AttachToProcess (pid);
+
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%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);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_D (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // Scope for mutex locker.
+ Mutex::Locker locker (m_spawned_pids_mutex);
+
+ // 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 ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ if (m_spawned_pids.find(m_debugged_process_sp->GetID ()) == m_spawned_pids.end())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to find PID %" PRIu64 " in spawned pids list",
+ __FUNCTION__, m_debugged_process_sp->GetID ());
+ return SendErrorResponse (0x1);
+ }
+
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ // Consume the ';' after D.
+ packet.SetFilePos (1);
+ if (packet.GetBytesLeft ())
+ {
+ if (packet.GetChar () != ';')
+ return SendIllFormedResponse (packet, "D missing expected ';'");
+
+ // Grab the PID from which we will detach (assume hex encoding).
+ pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16);
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendIllFormedResponse (packet, "D failed to parse the process id");
+ }
+
+ if (pid != LLDB_INVALID_PROCESS_ID &&
+ m_debugged_process_sp->GetID () != pid)
+ {
+ return SendIllFormedResponse (packet, "Invalid pid");
+ }
+
+ if (m_stdio_communication.IsConnected ())
+ {
+ m_stdio_communication.StopReadThread ();
+ }
+
+ const Error error = m_debugged_process_sp->Detach ();
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to detach from pid %" PRIu64 ": %s\n",
+ __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x01);
+ }
+
+ m_spawned_pids.erase (m_debugged_process_sp->GetID ());
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ packet.SetFilePos (strlen("qThreadStopInfo"));
+ const lldb::tid_t tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID);
+ if (tid == LLDB_INVALID_THREAD_ID)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse thread id from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return SendErrorResponse (0x15);
+ }
+ return SendStopReplyPacketForThread (tid);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet)
+{
+ // 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);
+
+ packet.SetFilePos(strlen("qWatchpointSupportInfo"));
+ if (packet.GetBytesLeft() == 0)
+ return SendOKResponse();
+ if (packet.GetChar() != ':')
+ return SendErrorResponse(67);
+
+ uint32_t num = m_debugged_process_sp->GetMaxWatchpoints();
+ StreamGDBRemote response;
+ response.Printf ("num:%d;", num);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress (StringExtractorGDBRemote &packet)
+{
+ // 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(67);
+
+ packet.SetFilePos(strlen("qFileLoadAddress:"));
+ if (packet.GetBytesLeft() == 0)
+ return SendErrorResponse(68);
+
+ std::string file_name;
+ packet.GetHexByteString(file_name);
+
+ lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS;
+ Error error = m_debugged_process_sp->GetFileLoadAddress(file_name, file_load_address);
+ if (error.Fail())
+ return SendErrorResponse(69);
+
+ if (file_load_address == LLDB_INVALID_ADDRESS)
+ return SendErrorResponse(1); // File not loaded
+
+ StreamGDBRemote response;
+ response.PutHex64(file_load_address);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+void
+GDBRemoteCommunicationServerLLGS::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 ("GDBRemoteCommunicationServerLLGS::%s() called", __FUNCTION__);
+
+ // FIXME implement a timeout on the join.
+ m_stdio_communication.JoinReadThread();
+}
+
+void
+GDBRemoteCommunicationServerLLGS::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 ("GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - SUCCESS", __FUNCTION__);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - FAIL: %s", __FUNCTION__, error.AsCString ());
+ }
+ }
+ }
+}
+
+
+NativeThreadProtocolSP
+GDBRemoteCommunicationServerLLGS::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 ("GDBRemoteCommunicationServerLLGS::%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 ("GDBRemoteCommunicationServerLLGS::%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
+GDBRemoteCommunicationServerLLGS::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
+GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID ()
+{
+ Mutex::Locker locker (m_saved_registers_mutex);
+ return m_next_saved_registers_id++;
+}
+
+void
+GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData ()
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s()", __FUNCTION__);
+
+ // Clear any auxv cached data.
+ // *BSD impls should be able to do this too.
+#if defined(__linux__)
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s clearing auxv buffer (previously %s)",
+ __FUNCTION__,
+ m_active_auxv_buffer_sp ? "was set" : "was not set");
+ m_active_auxv_buffer_sp.reset ();
+#endif
+}
+
+FileSpec
+GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string& module_path,
+ const ArchSpec& arch)
+{
+ if (m_debugged_process_sp)
+ {
+ FileSpec file_spec;
+ if (m_debugged_process_sp->GetLoadedModuleFileSpec(module_path.c_str(), file_spec).Success())
+ {
+ if (file_spec.Exists())
+ return file_spec;
+ }
+ }
+
+ return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch);
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
new file mode 100644
index 000000000000..1eda0b052bb7
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -0,0 +1,307 @@
+//===-- GDBRemoteCommunicationServerLLGS.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_GDBRemoteCommunicationServerLLGS_h_
+#define liblldb_GDBRemoteCommunicationServerLLGS_h_
+
+// C Includes
+// C++ Includes
+#include <unordered_map>
+
+// Other libraries and framework includes
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+
+// Project includes
+#include "GDBRemoteCommunicationServerCommon.h"
+
+class StringExtractorGDBRemote;
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunicationServerLLGS :
+ public GDBRemoteCommunicationServerCommon,
+ public NativeProcessProtocol::NativeDelegate
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunicationServerLLGS(const lldb::PlatformSP& platform_sp);
+
+ virtual
+ ~GDBRemoteCommunicationServerLLGS();
+
+ //------------------------------------------------------------------
+ /// Specify the program to launch and its arguments.
+ ///
+ /// @param[in] args
+ /// The command line to launch.
+ ///
+ /// @param[in] argc
+ /// The number of elements in the args array of cstring pointers.
+ ///
+ /// @return
+ /// An Error object indicating the success or failure of making
+ /// the setting.
+ //------------------------------------------------------------------
+ Error
+ SetLaunchArguments (const char *const args[], int argc);
+
+ //------------------------------------------------------------------
+ /// Specify the launch flags for the process.
+ ///
+ /// @param[in] launch_flags
+ /// The launch flags to use when launching this process.
+ ///
+ /// @return
+ /// An Error object indicating the success or failure of making
+ /// the setting.
+ //------------------------------------------------------------------
+ Error
+ SetLaunchFlags (unsigned int launch_flags);
+
+ //------------------------------------------------------------------
+ /// Launch a process with the current launch settings.
+ ///
+ /// This method supports running an lldb-gdbserver or similar
+ /// server in a situation where the startup code has been provided
+ /// with all the information for a child process to be launched.
+ ///
+ /// @return
+ /// An Error object indicating the success or failure of the
+ /// launch.
+ //------------------------------------------------------------------
+ Error
+ LaunchProcess () override;
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ Error
+ AttachToProcess (lldb::pid_t pid);
+
+ //------------------------------------------------------------------
+ // NativeProcessProtocol::NativeDelegate overrides
+ //------------------------------------------------------------------
+ void
+ InitializeDelegate (NativeProcessProtocol *process) override;
+
+ void
+ ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) override;
+
+ void
+ DidExec (NativeProcessProtocol *process) override;
+
+protected:
+ lldb::PlatformSP m_platform_sp;
+ lldb::thread_t m_async_thread;
+ lldb::tid_t m_current_tid;
+ lldb::tid_t m_continue_tid;
+ Mutex m_debugged_process_mutex;
+ NativeProcessProtocolSP m_debugged_process_sp;
+ Communication m_stdio_communication;
+ lldb::StateType m_inferior_prev_state;
+ lldb::DataBufferSP m_active_auxv_buffer_sp;
+ Mutex m_saved_registers_mutex;
+ std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map;
+ uint32_t m_next_saved_registers_id;
+
+ PacketResult
+ SendONotification (const char *buffer, uint32_t len);
+
+ PacketResult
+ SendWResponse (NativeProcessProtocol *process);
+
+ PacketResult
+ SendStopReplyPacketForThread (lldb::tid_t tid);
+
+ PacketResult
+ SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit);
+
+ PacketResult
+ Handle_k (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qProcessInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qC (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetWorkingDir (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qGetWorkingDir (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_C (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_c (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vCont (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vCont_actions (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_stop_reason (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_I (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_qXfer_auxv_read (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSaveRegisterState (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vAttach (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_D (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qThreadStopInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qFileLoadAddress (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; }
+
+ Error
+ SetSTDIOFileDescriptor (int fd);
+
+ static void
+ STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
+
+ FileSpec
+ FindModuleFile (const std::string& module_path, const ArchSpec& arch) override;
+
+private:
+ bool
+ DebuggedProcessReaped (lldb::pid_t pid);
+
+ static bool
+ ReapDebuggedProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal,
+ int status);
+
+ void
+ HandleInferiorState_Exited (NativeProcessProtocol *process);
+
+ void
+ HandleInferiorState_Stopped (NativeProcessProtocol *process);
+
+ void
+ FlushInferiorOutput ();
+
+ NativeThreadProtocolSP
+ GetThreadFromSuffix (StringExtractorGDBRemote &packet);
+
+ uint32_t
+ GetNextSavedRegistersID ();
+
+ void
+ MaybeCloseInferiorTerminalConnection ();
+
+ void
+ ClearProcessSpecificData ();
+
+ void
+ RegisterPacketHandlers ();
+
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunicationServerLLGS only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServerLLGS);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_GDBRemoteCommunicationServerLLGS_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
new file mode 100644
index 000000000000..f5e5d76f2e6f
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
@@ -0,0 +1,376 @@
+//===-- GDBRemoteCommunicationServerPlatform.cpp ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteCommunicationServerPlatform.h"
+
+#include <errno.h>
+
+// C Includes
+// C++ Includes
+#include <cstring>
+#include <chrono>
+
+// Other libraries and framework includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Target/FileAction.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "Utility/UriParser.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunicationServerPlatform constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform() :
+ GDBRemoteCommunicationServerCommon ("gdb-remote.server", "gdb-remote.server.rx_packet"),
+ m_platform_sp (Platform::GetHostPlatform ()),
+ m_port_map (),
+ m_port_offset(0)
+{
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC,
+ &GDBRemoteCommunicationServerPlatform::Handle_qC);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
+ &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer,
+ &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
+ &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
+ &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
+
+ RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
+ [this](StringExtractorGDBRemote packet,
+ Error &error,
+ bool &interrupt,
+ bool &quit)
+ {
+ error.SetErrorString("interrupt received");
+ interrupt = true;
+ return PacketResult::Success;
+ });
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform()
+{
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+ return SendErrorResponse(9);
+#else
+ // Spawn a local debugserver as a platform so we can then attach or launch
+ // a process...
+
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__);
+
+ // Sleep and wait a bit for debugserver to start to listen...
+ ConnectionFileDescriptor file_conn;
+ std::string hostname;
+ // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
+ // with the TMPDIR environment variable
+ packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
+ std::string name;
+ std::string value;
+ uint16_t port = UINT16_MAX;
+ while (packet.GetNameColonValue(name, value))
+ {
+ if (name.compare ("host") == 0)
+ hostname.swap(value);
+ else if (name.compare ("port") == 0)
+ port = StringConvert::ToUInt32(value.c_str(), 0, 0);
+ }
+ if (port == UINT16_MAX)
+ port = GetNextAvailablePort();
+
+ // Spawn a new thread to accept the port that gets bound after
+ // binding to port 0 (zero).
+
+ // ignore the hostname send from the remote end, just use the ip address
+ // that we're currently communicating with as the hostname
+
+ // 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...", hostname.c_str(), port);
+
+ // Do not run in a new session so that it can not linger after the
+ // platform closes.
+ debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
+ debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
+
+ std::string platform_scheme;
+ std::string platform_ip;
+ int platform_port;
+ std::string platform_path;
+ bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path);
+ assert(ok);
+ Error error = StartDebugserverProcess (
+ platform_ip.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())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerPlatform::%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 ("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ());
+ }
+ return SendErrorResponse (9);
+#endif
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo (StringExtractorGDBRemote &packet)
+{
+ lldb::pid_t pid = m_process_launch_info.GetProcessID ();
+ m_process_launch_info.Clear ();
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse (1);
+
+ ProcessInstanceInfo proc_info;
+ if (!Host::GetProcessInfo (pid, proc_info))
+ return SendErrorResponse (1);
+
+ StreamString response;
+ CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ // If this packet is sent to a platform, then change the current working directory
+
+ char cwd[PATH_MAX];
+ if (getcwd(cwd, sizeof(cwd)) == NULL)
+ return SendErrorResponse(errno);
+
+ StreamString response;
+ response.PutBytesAsRawHex8(cwd, strlen(cwd));
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos (::strlen ("QSetWorkingDir:"));
+ std::string path;
+ packet.GetHexByteString (path);
+
+ // If this packet is sent to a platform, then change the current working directory
+ if (::chdir(path.c_str()) != 0)
+ return SendErrorResponse (errno);
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qC (StringExtractorGDBRemote &packet)
+{
+ // 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();
+
+ StreamString response;
+ response.Printf("QC%" PRIx64, pid);
+
+ // 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());
+}
+
+bool
+GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped (lldb::pid_t pid)
+{
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ FreePortForProcess(pid);
+ return m_spawned_pids.erase(pid) > 0;
+}
+
+bool
+GDBRemoteCommunicationServerPlatform::ReapDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal, // Zero for no signal
+ int status) // Exit value of process if signal is zero
+{
+ GDBRemoteCommunicationServerPlatform *server = (GDBRemoteCommunicationServerPlatform *)callback_baton;
+ server->DebugserverProcessReaped (pid);
+ return true;
+}
+
+Error
+GDBRemoteCommunicationServerPlatform::LaunchProcess ()
+{
+ if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
+ return Error ("%s: no process command line specified to launch", __FUNCTION__);
+
+ // specify the process monitor if not already set. This should
+ // generally be what happens since we need to reap started
+ // processes.
+ if (!m_process_launch_info.GetMonitorProcessCallback ())
+ m_process_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
+
+ Error error = m_platform_sp->LaunchProcess (m_process_launch_info);
+ if (!error.Success ())
+ {
+ fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0));
+ return error;
+ }
+
+ 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. On an lldb-gdbserver, we
+ // would expect there to be only one.
+ const auto pid = m_process_launch_info.GetProcessID();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ // add to spawned pids
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ m_spawned_pids.insert(pid);
+ }
+
+ return error;
+}
+
+void
+GDBRemoteCommunicationServerPlatform::SetPortMap (PortMap &&port_map)
+{
+ m_port_map = port_map;
+}
+
+uint16_t
+GDBRemoteCommunicationServerPlatform::GetNextAvailablePort ()
+{
+ if (m_port_map.empty())
+ return 0; // Bind to port zero and get a port, we didn't have any limitations
+
+ for (auto &pair : m_port_map)
+ {
+ if (pair.second == LLDB_INVALID_PROCESS_ID)
+ {
+ pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
+ return pair.first;
+ }
+ }
+ return UINT16_MAX;
+}
+
+bool
+GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess (uint16_t port, lldb::pid_t pid)
+{
+ PortMap::iterator pos = m_port_map.find(port);
+ if (pos != m_port_map.end())
+ {
+ pos->second = pid;
+ return true;
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationServerPlatform::FreePort (uint16_t port)
+{
+ PortMap::iterator pos = m_port_map.find(port);
+ if (pos != m_port_map.end())
+ {
+ pos->second = LLDB_INVALID_PROCESS_ID;
+ return true;
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationServerPlatform::FreePortForProcess (lldb::pid_t pid)
+{
+ if (!m_port_map.empty())
+ {
+ for (auto &pair : m_port_map)
+ {
+ if (pair.second == pid)
+ {
+ pair.second = LLDB_INVALID_PROCESS_ID;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void
+GDBRemoteCommunicationServerPlatform::SetPortOffset (uint16_t port_offset)
+{
+ m_port_offset = port_offset;
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
new file mode 100644
index 000000000000..4124b0424f5d
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
@@ -0,0 +1,102 @@
+//===-- GDBRemoteCommunicationServerPlatform.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_GDBRemoteCommunicationServerPlatform_h_
+#define liblldb_GDBRemoteCommunicationServerPlatform_h_
+
+#include "GDBRemoteCommunicationServerCommon.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class GDBRemoteCommunicationServerPlatform :
+ public GDBRemoteCommunicationServerCommon
+{
+public:
+ typedef std::map<uint16_t, lldb::pid_t> PortMap;
+
+ GDBRemoteCommunicationServerPlatform();
+
+ virtual
+ ~GDBRemoteCommunicationServerPlatform();
+
+ Error
+ LaunchProcess () override;
+
+ // Set both ports to zero to let the platform automatically bind to
+ // a port chosen by the OS.
+ void
+ SetPortMap (PortMap &&port_map);
+
+ //----------------------------------------------------------------------
+ // If we are using a port map where we can only use certain ports,
+ // get the next available port.
+ //
+ // If we are using a port map and we are out of ports, return UINT16_MAX
+ //
+ // If we aren't using a port map, return 0 to indicate we should bind to
+ // port 0 and then figure out which port we used.
+ //----------------------------------------------------------------------
+ uint16_t
+ GetNextAvailablePort ();
+
+ bool
+ AssociatePortWithProcess (uint16_t port, lldb::pid_t pid);
+
+ bool
+ FreePort (uint16_t port);
+
+ bool
+ FreePortForProcess (lldb::pid_t pid);
+
+ void
+ SetPortOffset (uint16_t port_offset);
+
+protected:
+ lldb::PlatformSP m_platform_sp;
+
+ PortMap m_port_map;
+ uint16_t m_port_offset;
+
+ PacketResult
+ Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qProcessInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qGetWorkingDir (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetWorkingDir (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qC (StringExtractorGDBRemote &packet);
+
+private:
+ bool
+ DebugserverProcessReaped (lldb::pid_t pid);
+
+ static bool
+ ReapDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal,
+ int status);
+
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunicationServerPlatform only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServerPlatform);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_GDBRemoteCommunicationServerPlatform_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
index 6d7eca1a0ced..f5f134e80d6a 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -33,6 +33,7 @@
using namespace lldb;
using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
//----------------------------------------------------------------------
// GDBRemoteRegisterContext constructor
@@ -151,7 +152,7 @@ GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor
// Helper function for GDBRemoteRegisterContext::ReadRegisterBytes().
bool
-GDBRemoteRegisterContext::GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+GDBRemoteRegisterContext::GetPrimordialRegister(const RegisterInfo *reg_info,
GDBRemoteCommunicationClient &gdb_comm)
{
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
@@ -265,7 +266,7 @@ GDBRemoteRegisterContext::WriteRegister (const RegisterInfo *reg_info,
// Helper function for GDBRemoteRegisterContext::WriteRegisterBytes().
bool
-GDBRemoteRegisterContext::SetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+GDBRemoteRegisterContext::SetPrimordialRegister(const RegisterInfo *reg_info,
GDBRemoteCommunicationClient &gdb_comm)
{
StreamString packet;
@@ -316,7 +317,7 @@ GDBRemoteRegisterContext::SyncThreadState(Process *process)
}
bool
-GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo *reg_info, DataExtractor &data, uint32_t data_offset)
+GDBRemoteRegisterContext::WriteRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data, uint32_t data_offset)
{
ExecutionContext exe_ctx (CalculateThread());
@@ -460,7 +461,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo *
}
bool
-GDBRemoteRegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint &reg_checkpoint)
+GDBRemoteRegisterContext::ReadAllRegisterValues (RegisterCheckpoint &reg_checkpoint)
{
ExecutionContext exe_ctx (CalculateThread());
@@ -486,7 +487,7 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoin
}
bool
-GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint &reg_checkpoint)
+GDBRemoteRegisterContext::WriteAllRegisterValues (const RegisterCheckpoint &reg_checkpoint)
{
uint32_t save_id = reg_checkpoint.GetID();
if (save_id != 0)
@@ -676,15 +677,16 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
// 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);
+
+ const uint32_t bytes_extracted = response.GetHexBytes (buffer.GetBytes(),
+ buffer.GetByteSize(),
+ '\xcc');
+
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());
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
index b77381458914..117d280cc547 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -25,9 +25,13 @@
#include "GDBRemoteCommunicationClient.h"
+class StringExtractor;
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
class ThreadGDBRemote;
class ProcessGDBRemote;
-class StringExtractor;
class GDBRemoteDynamicRegisterInfo :
public DynamicRegisterInfo
@@ -47,7 +51,7 @@ public:
};
-class GDBRemoteRegisterContext : public lldb_private::RegisterContext
+class GDBRemoteRegisterContext : public RegisterContext
{
public:
//------------------------------------------------------------------
@@ -64,52 +68,52 @@ public:
//------------------------------------------------------------------
// Subclasses must override these functions
//------------------------------------------------------------------
- virtual void
- InvalidateAllRegisters ();
+ void
+ InvalidateAllRegisters () override;
- virtual size_t
- GetRegisterCount ();
+ size_t
+ GetRegisterCount () override;
- virtual const lldb_private::RegisterInfo *
- GetRegisterInfoAtIndex (size_t reg);
+ const RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg) override;
- virtual size_t
- GetRegisterSetCount ();
+ size_t
+ GetRegisterSetCount () override;
- virtual const lldb_private::RegisterSet *
- GetRegisterSet (size_t reg_set);
+ const RegisterSet *
+ GetRegisterSet (size_t reg_set) override;
- virtual bool
- ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+ bool
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) override;
- virtual bool
- WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+ bool
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value) override;
- virtual bool
- ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+ bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override;
- virtual bool
- WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+ bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
- virtual bool
- ReadAllRegisterValues (lldb_private::RegisterCheckpoint &reg_checkpoint);
+ bool
+ ReadAllRegisterValues (RegisterCheckpoint &reg_checkpoint) override;
- virtual bool
- WriteAllRegisterValues (const lldb_private::RegisterCheckpoint &reg_checkpoint);
+ bool
+ WriteAllRegisterValues (const RegisterCheckpoint &reg_checkpoint) override;
- virtual uint32_t
- ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) override;
protected:
friend class ThreadGDBRemote;
bool
- ReadRegisterBytes (const lldb_private::RegisterInfo *reg_info,
- lldb_private::DataExtractor &data);
+ ReadRegisterBytes (const RegisterInfo *reg_info,
+ DataExtractor &data);
bool
- WriteRegisterBytes (const lldb_private::RegisterInfo *reg_info,
- lldb_private::DataExtractor &data,
+ WriteRegisterBytes (const RegisterInfo *reg_info,
+ DataExtractor &data,
uint32_t data_offset);
bool
@@ -130,7 +134,7 @@ protected:
}
void
- SetRegisterIsValid (const lldb_private::RegisterInfo *reg_info, bool valid)
+ SetRegisterIsValid (const RegisterInfo *reg_info, bool valid)
{
if (reg_info)
return SetRegisterIsValid (reg_info->kinds[lldb::eRegisterKindLLDB], valid);
@@ -147,19 +151,19 @@ protected:
}
void
- SyncThreadState(lldb_private::Process *process); // Assumes the sequence mutex has already been acquired.
+ SyncThreadState(Process *process); // Assumes the sequence mutex has already been acquired.
GDBRemoteDynamicRegisterInfo &m_reg_info;
std::vector<bool> m_reg_valid;
- lldb_private::DataExtractor m_reg_data;
+ DataExtractor m_reg_data;
bool m_read_all_at_once;
private:
// Helper function for ReadRegisterBytes().
- bool GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+ bool GetPrimordialRegister(const RegisterInfo *reg_info,
GDBRemoteCommunicationClient &gdb_comm);
// Helper function for WriteRegisterBytes().
- bool SetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+ bool SetPrimordialRegister(const RegisterInfo *reg_info,
GDBRemoteCommunicationClient &gdb_comm);
//------------------------------------------------------------------
@@ -168,4 +172,7 @@ private:
DISALLOW_COPY_AND_ASSIGN (GDBRemoteRegisterContext);
};
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
#endif // lldb_GDBRemoteRegisterContext_h_
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index cb0b4bb51007..5cb4da514a7f 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
#include "lldb/Host/Config.h"
// C Includes
@@ -24,8 +23,7 @@
// C++ Includes
#include <algorithm>
#include <map>
-
-// Other libraries and framework includes
+#include <mutex>
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Interpreter/Args.h"
@@ -41,18 +39,22 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
#include "lldb/Core/Value.h"
+#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Host/Symbols.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Host/TimeValue.h"
+#include "lldb/Host/XML.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandObjectMultiword.h"
#include "lldb/Interpreter/CommandReturnObject.h"
-#ifndef LLDB_DISABLE_PYTHON
-#include "lldb/Interpreter/PythonDataObjects.h"
-#endif
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupBoolean.h"
+#include "lldb/Interpreter/OptionGroupUInt64.h"
+#include "lldb/Interpreter/Property.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/Target.h"
@@ -66,6 +68,7 @@
#include "Plugins/Process/Utility/FreeBSDSignals.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
#include "Plugins/Process/Utility/LinuxSignals.h"
+#include "Plugins/Process/Utility/MipsLinuxSignals.h"
#include "Plugins/Process/Utility/StopInfoMachException.h"
#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
#include "Utility/StringExtractorGDBRemote.h"
@@ -74,6 +77,10 @@
#include "ProcessGDBRemoteLog.h"
#include "ThreadGDBRemote.h"
+#define DEBUGSERVER_BASENAME "debugserver"
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
namespace lldb
{
@@ -86,18 +93,13 @@ namespace lldb
void
DumpProcessGDBRemotePacketHistory (void *p, const char *path)
{
- lldb_private::StreamFile strm;
- lldb_private::Error error (strm.GetFile().Open(path, lldb_private::File::eOpenOptionWrite | lldb_private::File::eOpenOptionCanCreate));
+ StreamFile strm;
+ Error error (strm.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate));
if (error.Success())
((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory (strm);
}
}
-#define DEBUGSERVER_BASENAME "debugserver"
-using namespace lldb;
-using namespace lldb_private;
-
-
namespace {
static PropertyDefinition
@@ -171,6 +173,107 @@ namespace {
} // anonymous namespace end
+class ProcessGDBRemote::GDBLoadedModuleInfoList
+{
+public:
+
+ class LoadedModuleInfo
+ {
+ public:
+
+ enum e_data_point
+ {
+ e_has_name = 0,
+ e_has_base ,
+ e_has_dynamic ,
+ e_has_link_map ,
+ e_num
+ };
+
+ LoadedModuleInfo ()
+ {
+ for (uint32_t i = 0; i < e_num; ++i)
+ m_has[i] = false;
+ };
+
+ void set_name (const std::string & name)
+ {
+ m_name = name;
+ m_has[e_has_name] = true;
+ }
+ bool get_name (std::string & out) const
+ {
+ out = m_name;
+ return m_has[e_has_name];
+ }
+
+ void set_base (const lldb::addr_t base)
+ {
+ m_base = base;
+ m_has[e_has_base] = true;
+ }
+ bool get_base (lldb::addr_t & out) const
+ {
+ out = m_base;
+ return m_has[e_has_base];
+ }
+
+ void set_link_map (const lldb::addr_t addr)
+ {
+ m_link_map = addr;
+ m_has[e_has_link_map] = true;
+ }
+ bool get_link_map (lldb::addr_t & out) const
+ {
+ out = m_link_map;
+ return m_has[e_has_link_map];
+ }
+
+ void set_dynamic (const lldb::addr_t addr)
+ {
+ m_dynamic = addr;
+ m_has[e_has_dynamic] = true;
+ }
+ bool get_dynamic (lldb::addr_t & out) const
+ {
+ out = m_dynamic;
+ return m_has[e_has_dynamic];
+ }
+
+ bool has_info (e_data_point datum)
+ {
+ assert (datum < e_num);
+ return m_has[datum];
+ }
+
+ protected:
+
+ bool m_has[e_num];
+ std::string m_name;
+ lldb::addr_t m_link_map;
+ lldb::addr_t m_base;
+ lldb::addr_t m_dynamic;
+ };
+
+ GDBLoadedModuleInfoList ()
+ : m_list ()
+ , m_link_map (LLDB_INVALID_ADDRESS)
+ {}
+
+ void add (const LoadedModuleInfo & mod)
+ {
+ m_list.push_back (mod);
+ }
+
+ void clear ()
+ {
+ m_list.clear ();
+ }
+
+ std::vector<LoadedModuleInfo> m_list;
+ lldb::addr_t m_link_map;
+};
+
// 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.
@@ -200,7 +303,7 @@ get_random_port ()
}
#endif
-lldb_private::ConstString
+ConstString
ProcessGDBRemote::GetPluginNameStatic()
{
static ConstString g_name("gdb-remote");
@@ -268,14 +371,14 @@ ProcessGDBRemote::CanDebug (Target &target, bool plugin_specified_by_name)
ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
Process (target, listener),
m_flags (0),
- m_gdb_comm(false),
+ m_gdb_comm (),
m_debugserver_pid (LLDB_INVALID_PROCESS_ID),
- m_last_stop_packet (),
m_last_stop_packet_mutex (Mutex::eMutexTypeNormal),
m_register_info (),
m_async_broadcaster (NULL, "lldb.process.gdb-remote.async-broadcaster"),
m_async_thread_state_mutex(Mutex::eMutexTypeRecursive),
m_thread_ids (),
+ m_threads_info_sp (),
m_continue_c_tids (),
m_continue_C_tids (),
m_continue_s_tids (),
@@ -287,7 +390,8 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
m_waiting_for_attach (false),
m_destroy_tried_resuming (false),
m_command_sp (),
- m_breakpoint_pc_offset (0)
+ m_breakpoint_pc_offset (0),
+ m_initial_tid (LLDB_INVALID_THREAD_ID)
{
m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit");
m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue");
@@ -335,44 +439,69 @@ ProcessGDBRemote::GetPluginVersion()
bool
ProcessGDBRemote::ParsePythonTargetDefinition(const FileSpec &target_definition_fspec)
{
-#ifndef LLDB_DISABLE_PYTHON
ScriptInterpreter *interpreter = GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
Error error;
- lldb::ScriptInterpreterObjectSP module_object_sp (interpreter->LoadPluginModule(target_definition_fspec, error));
+ StructuredData::ObjectSP module_object_sp(interpreter->LoadPluginModule(target_definition_fspec, error));
if (module_object_sp)
{
- lldb::ScriptInterpreterObjectSP target_definition_sp (interpreter->GetDynamicSettings(module_object_sp,
- &GetTarget(),
- "gdb-server-target-definition",
- error));
-
- PythonDictionary target_dict(target_definition_sp);
+ StructuredData::DictionarySP target_definition_sp(
+ interpreter->GetDynamicSettings(module_object_sp, &GetTarget(), "gdb-server-target-definition", error));
- if (target_dict)
+ if (target_definition_sp)
{
- PythonDictionary host_info_dict (target_dict.GetItemForKey("host-info"));
- if (host_info_dict)
+ StructuredData::ObjectSP target_object(target_definition_sp->GetValueForKey("host-info"));
+ if (target_object)
{
- ArchSpec host_arch (host_info_dict.GetItemForKeyAsString(PythonString("triple")));
-
- if (!host_arch.IsCompatibleMatch(GetTarget().GetArchitecture()))
+ if (auto host_info_dict = target_object->GetAsDictionary())
{
- GetTarget().SetArchitecture(host_arch);
+ StructuredData::ObjectSP triple_value = host_info_dict->GetValueForKey("triple");
+ if (auto triple_string_value = triple_value->GetAsString())
+ {
+ std::string triple_string = triple_string_value->GetValue();
+ ArchSpec host_arch(triple_string.c_str());
+ if (!host_arch.IsCompatibleMatch(GetTarget().GetArchitecture()))
+ {
+ GetTarget().SetArchitecture(host_arch);
+ }
+ }
}
-
}
- m_breakpoint_pc_offset = target_dict.GetItemForKeyAsInteger("breakpoint-pc-offset", 0);
+ m_breakpoint_pc_offset = 0;
+ StructuredData::ObjectSP breakpoint_pc_offset_value = target_definition_sp->GetValueForKey("breakpoint-pc-offset");
+ if (breakpoint_pc_offset_value)
+ {
+ if (auto breakpoint_pc_int_value = breakpoint_pc_offset_value->GetAsInteger())
+ m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue();
+ }
- if (m_register_info.SetRegisterInfo (target_dict, GetTarget().GetArchitecture().GetByteOrder()) > 0)
+ if (m_register_info.SetRegisterInfo(*target_definition_sp, GetTarget().GetArchitecture()) > 0)
{
return true;
}
}
}
-#endif
return false;
}
+static size_t
+SplitCommaSeparatedRegisterNumberString(const llvm::StringRef &comma_separated_regiter_numbers, std::vector<uint32_t> &regnums, int base)
+{
+ regnums.clear();
+ std::pair<llvm::StringRef, llvm::StringRef> value_pair;
+ value_pair.second = comma_separated_regiter_numbers;
+ do
+ {
+ value_pair = value_pair.second.split(',');
+ if (!value_pair.first.empty())
+ {
+ uint32_t reg = StringConvert::ToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, base);
+ if (reg != LLDB_INVALID_REGNUM)
+ regnums.push_back (reg);
+ }
+ } while (!value_pair.second.empty());
+ return regnums.size();
+}
+
void
ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
@@ -380,8 +509,34 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
if (!force && m_register_info.GetNumRegisters() > 0)
return;
- char packet[128];
m_register_info.Clear();
+
+ // Check if qHostInfo specified a specific packet timeout for this connection.
+ // If so then lets update our setting so the user knows what the timeout is
+ // and can see it.
+ const uint32_t host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout();
+ if (host_packet_timeout)
+ {
+ GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout);
+ }
+
+ // Register info search order:
+ // 1 - Use the target definition python file if one is specified.
+ // 2 - If the target definition doesn't have any of the info from the target.xml (registers) then proceed to read the target.xml.
+ // 3 - Fall back on the qRegisterInfo packets.
+
+ FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile ();
+ if (target_definition_fspec)
+ {
+ // See if we can get register definitions from a python file
+ if (ParsePythonTargetDefinition (target_definition_fspec))
+ return;
+ }
+
+ if (GetGDBServerRegisterInfo ())
+ return;
+
+ char packet[128];
uint32_t reg_offset = 0;
uint32_t reg_num = 0;
for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse;
@@ -496,33 +651,11 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
}
else if (name.compare("container-regs") == 0)
{
- std::pair<llvm::StringRef, llvm::StringRef> value_pair;
- value_pair.second = value;
- do
- {
- value_pair = value_pair.second.split(',');
- if (!value_pair.first.empty())
- {
- uint32_t reg = StringConvert::ToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, 16);
- if (reg != LLDB_INVALID_REGNUM)
- value_regs.push_back (reg);
- }
- } while (!value_pair.second.empty());
+ SplitCommaSeparatedRegisterNumberString(value, value_regs, 16);
}
else if (name.compare("invalidate-regs") == 0)
{
- std::pair<llvm::StringRef, llvm::StringRef> value_pair;
- value_pair.second = value;
- do
- {
- value_pair = value_pair.second.split(',');
- if (!value_pair.first.empty())
- {
- uint32_t reg = StringConvert::ToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, 16);
- if (reg != LLDB_INVALID_REGNUM)
- invalidate_regs.push_back (reg);
- }
- } while (!value_pair.second.empty());
+ SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 16);
}
}
@@ -553,26 +686,10 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
}
}
- // Check if qHostInfo specified a specific packet timeout for this connection.
- // If so then lets update our setting so the user knows what the timeout is
- // and can see it.
- const uint32_t host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout();
- if (host_packet_timeout)
+ if (m_register_info.GetNumRegisters() > 0)
{
- GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout);
- }
-
-
- if (reg_num == 0)
- {
- FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile ();
-
- if (target_definition_fspec)
- {
- // See if we can get register definitions from a python file
- if (ParsePythonTargetDefinition (target_definition_fspec))
- return;
- }
+ m_register_info.Finalize(GetTarget().GetArchitecture());
+ return;
}
// We didn't get anything if the accumulated reg_num is zero. See if we are
@@ -580,7 +697,7 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
// updated debugserver down on the devices.
// On the other hand, if the accumulated reg_num is positive, see if we can
// add composite registers to the existing primordial ones.
- bool from_scratch = (reg_num == 0);
+ bool from_scratch = (m_register_info.GetNumRegisters() == 0);
const ArchSpec &target_arch = GetTarget().GetArchitecture();
const ArchSpec &remote_host_arch = m_gdb_comm.GetHostArchitecture();
@@ -606,7 +723,7 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
}
// At this point, we can finalize our register info.
- m_register_info.Finalize ();
+ m_register_info.Finalize (GetTarget().GetArchitecture());
}
Error
@@ -655,8 +772,15 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
// We have a valid process
SetID (pid);
GetThreadList();
- if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success)
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.GetStopReply(response))
{
+ SetLastStopPacket(response);
+
+ // '?' Packets must be handled differently in non-stop mode
+ if (GetTarget().GetNonStopModeEnabled())
+ HandleStopReplySequence();
+
if (!m_target.GetArchitecture().IsValid())
{
if (m_gdb_comm.GetProcessArchitecture().IsValid())
@@ -669,7 +793,7 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
}
}
- const StateType state = SetThreadStopInfo (m_last_stop_packet);
+ const StateType state = SetThreadStopInfo (response);
if (state == eStateStopped)
{
SetPrivateState (state);
@@ -703,7 +827,7 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
// FIXME Add a gdb-remote packet to discover dynamically.
if (error.Success ())
{
- const ArchSpec arch_spec = GetTarget ().GetArchitecture ();
+ const ArchSpec arch_spec = m_gdb_comm.GetHostArchitecture();
if (arch_spec.IsValid ())
{
if (log)
@@ -712,7 +836,10 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
switch (arch_spec.GetTriple ().getOS ())
{
case llvm::Triple::Linux:
- SetUnixSignals (UnixSignalsSP (new process_linux::LinuxSignals ()));
+ if (arch_spec.GetTriple ().getArch () == llvm::Triple::mips64 || arch_spec.GetTriple ().getArch () == llvm::Triple::mips64el)
+ SetUnixSignals (UnixSignalsSP (new process_linux::MipsLinuxSignals ()));
+ else
+ SetUnixSignals (UnixSignalsSP (new process_linux::LinuxSignals ()));
if (log)
log->Printf ("ProcessGDBRemote::%s using Linux unix signals type for pid %" PRIu64, __FUNCTION__, GetID ());
break;
@@ -756,43 +883,55 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
log->Printf ("ProcessGDBRemote::%s() entered", __FUNCTION__);
uint32_t launch_flags = launch_info.GetFlags().Get();
- const char *stdin_path = NULL;
- const char *stdout_path = NULL;
- const char *stderr_path = NULL;
- const char *working_dir = launch_info.GetWorkingDirectory();
+ FileSpec stdin_file_spec{};
+ FileSpec stdout_file_spec{};
+ FileSpec stderr_file_spec{};
+ FileSpec working_dir = launch_info.GetWorkingDirectory();
const FileAction *file_action;
file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
if (file_action)
{
if (file_action->GetAction() == FileAction::eFileActionOpen)
- stdin_path = file_action->GetPath();
+ stdin_file_spec = file_action->GetFileSpec();
}
file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
if (file_action)
{
if (file_action->GetAction() == FileAction::eFileActionOpen)
- stdout_path = file_action->GetPath();
+ stdout_file_spec = file_action->GetFileSpec();
}
file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
if (file_action)
{
if (file_action->GetAction() == FileAction::eFileActionOpen)
- stderr_path = file_action->GetPath();
+ stderr_file_spec = file_action->GetFileSpec();
}
if (log)
{
- if (stdin_path || stdout_path || stderr_path)
- log->Printf ("ProcessGDBRemote::%s provided with STDIO paths via launch_info: stdin=%s, stdout=%s, stdout=%s",
+ if (stdin_file_spec || stdout_file_spec || stderr_file_spec)
+ log->Printf ("ProcessGDBRemote::%s provided with STDIO paths via launch_info: stdin=%s, stdout=%s, stderr=%s",
__FUNCTION__,
- stdin_path ? stdin_path : "<null>",
- stdout_path ? stdout_path : "<null>",
- stderr_path ? stderr_path : "<null>");
+ stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
+ stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
+ stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
else
log->Printf ("ProcessGDBRemote::%s no STDIO paths given via launch_info", __FUNCTION__);
}
+ const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
+ if (stdin_file_spec || disable_stdio)
+ {
+ // the inferior will be reading stdin from the specified file
+ // or stdio is completely disabled
+ m_stdin_forward = false;
+ }
+ else
+ {
+ m_stdin_forward = true;
+ }
+
// ::LogSetBitMask (GDBR_LOG_DEFAULT);
// ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
// ::LogSetLogFile ("/dev/stdout");
@@ -811,64 +950,58 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
lldb_utility::PseudoTerminal pty;
const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
- // If the debugserver is local and we aren't disabling STDIO, lets use
- // a pseudo terminal to instead of relying on the 'O' packets for stdio
- // since 'O' packets can really slow down debugging if the inferior
- // does a lot of output.
PlatformSP platform_sp (m_target.GetPlatform());
- if (platform_sp && platform_sp->IsHost() && !disable_stdio)
+ if (disable_stdio)
+ {
+ // set to /dev/null unless redirected to a file above
+ if (!stdin_file_spec)
+ stdin_file_spec.SetFile("/dev/null", false);
+ if (!stdout_file_spec)
+ stdout_file_spec.SetFile("/dev/null", false);
+ if (!stderr_file_spec)
+ stderr_file_spec.SetFile("/dev/null", false);
+ }
+ else if (platform_sp && platform_sp->IsHost())
{
- const char *slave_name = NULL;
- if (stdin_path == NULL || stdout_path == NULL || stderr_path == NULL)
+ // If the debugserver is local and we aren't disabling STDIO, lets use
+ // a pseudo terminal to instead of relying on the 'O' packets for stdio
+ // since 'O' packets can really slow down debugging if the inferior
+ // does a lot of output.
+ if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&
+ pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, NULL, 0))
{
- if (pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, NULL, 0))
- slave_name = pty.GetSlaveName (NULL, 0);
- }
- if (stdin_path == NULL)
- stdin_path = slave_name;
+ FileSpec slave_name{pty.GetSlaveName(NULL, 0), false};
- if (stdout_path == NULL)
- stdout_path = slave_name;
+ if (!stdin_file_spec)
+ stdin_file_spec = slave_name;
- if (stderr_path == NULL)
- stderr_path = slave_name;
+ if (!stdout_file_spec)
+ stdout_file_spec = slave_name;
+ if (!stderr_file_spec)
+ stderr_file_spec = slave_name;
+ }
if (log)
- log->Printf ("ProcessGDBRemote::%s adjusted STDIO paths for local platform (IsHost() is true) using slave: stdin=%s, stdout=%s, stdout=%s",
+ log->Printf ("ProcessGDBRemote::%s adjusted STDIO paths for local platform (IsHost() is true) using slave: stdin=%s, stdout=%s, stderr=%s",
__FUNCTION__,
- stdin_path ? stdin_path : "<null>",
- stdout_path ? stdout_path : "<null>",
- stderr_path ? stderr_path : "<null>");
+ stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
+ stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
+ stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
}
- // Set STDIN to /dev/null if we want STDIO disabled or if either
- // STDOUT or STDERR have been set to something and STDIN hasn't
- if (disable_stdio || (stdin_path == NULL && (stdout_path || stderr_path)))
- stdin_path = "/dev/null";
-
- // Set STDOUT to /dev/null if we want STDIO disabled or if either
- // STDIN or STDERR have been set to something and STDOUT hasn't
- if (disable_stdio || (stdout_path == NULL && (stdin_path || stderr_path)))
- stdout_path = "/dev/null";
-
- // Set STDERR to /dev/null if we want STDIO disabled or if either
- // STDIN or STDOUT have been set to something and STDERR hasn't
- if (disable_stdio || (stderr_path == NULL && (stdin_path || stdout_path)))
- stderr_path = "/dev/null";
-
if (log)
- log->Printf ("ProcessGDBRemote::%s final STDIO paths after all adjustments: stdin=%s, stdout=%s, stdout=%s",
+ log->Printf ("ProcessGDBRemote::%s final STDIO paths after all adjustments: stdin=%s, stdout=%s, stderr=%s",
__FUNCTION__,
- stdin_path ? stdin_path : "<null>",
- stdout_path ? stdout_path : "<null>",
- stderr_path ? stderr_path : "<null>");
+ stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
+ stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
+ stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
- if (stdin_path)
- m_gdb_comm.SetSTDIN (stdin_path);
- if (stdout_path)
- m_gdb_comm.SetSTDOUT (stdout_path);
- if (stderr_path)
- m_gdb_comm.SetSTDERR (stderr_path);
+ if (stdin_file_spec)
+ m_gdb_comm.SetSTDIN(stdin_file_spec);
+ if (stdout_file_spec)
+ m_gdb_comm.SetSTDOUT(stdout_file_spec);
+ if (stderr_file_spec)
+ m_gdb_comm.SetSTDERR(stderr_file_spec);
m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR);
m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError);
@@ -879,7 +1012,7 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
if (launch_event_data != NULL && *launch_event_data != '\0')
m_gdb_comm.SendLaunchEventDataPacket (launch_event_data);
- if (working_dir && working_dir[0])
+ if (working_dir)
{
m_gdb_comm.SetWorkingDir (working_dir);
}
@@ -897,27 +1030,29 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
}
}
- const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (10);
- int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info);
- if (arg_packet_err == 0)
{
- std::string error_str;
- if (m_gdb_comm.GetLaunchSuccess (error_str))
+ // Scope for the scoped timeout object
+ GDBRemoteCommunication::ScopedTimeout timeout (m_gdb_comm, 10);
+
+ int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info);
+ if (arg_packet_err == 0)
{
- SetID (m_gdb_comm.GetCurrentProcessID ());
+ std::string error_str;
+ if (m_gdb_comm.GetLaunchSuccess (error_str))
+ {
+ SetID (m_gdb_comm.GetCurrentProcessID ());
+ }
+ else
+ {
+ error.SetErrorString (error_str.c_str());
+ }
}
else
{
- error.SetErrorString (error_str.c_str());
+ error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err);
}
}
- else
- {
- error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err);
- }
-
- m_gdb_comm.SetPacketTimeout (old_packet_timeout);
-
+
if (GetID() == LLDB_INVALID_PROCESS_ID)
{
if (log)
@@ -926,23 +1061,29 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
return error;
}
- if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success)
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.GetStopReply(response))
{
- if (!m_target.GetArchitecture().IsValid())
+ SetLastStopPacket(response);
+ // '?' Packets must be handled differently in non-stop mode
+ if (GetTarget().GetNonStopModeEnabled())
+ HandleStopReplySequence();
+
+ const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();
+
+ if (process_arch.IsValid())
{
- if (m_gdb_comm.GetProcessArchitecture().IsValid())
- {
- m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture());
- }
- else
- {
- m_target.SetArchitecture(m_gdb_comm.GetHostArchitecture());
- }
+ m_target.MergeArchitecture(process_arch);
+ }
+ else
+ {
+ const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture();
+ if (host_arch.IsValid())
+ m_target.MergeArchitecture(host_arch);
}
- SetPrivateState (SetThreadStopInfo (m_last_stop_packet));
+ SetPrivateState (SetThreadStopInfo (response));
- m_stdio_disable = disable_stdio;
if (!disable_stdio)
{
if (pty.GetMasterFileDescriptor() != lldb_utility::PseudoTerminal::invalid_fd)
@@ -1015,6 +1156,12 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
return error;
}
+
+ // Start the communications read thread so all incoming data can be
+ // parsed into packets and queued as they arrive.
+ if (GetTarget().GetNonStopModeEnabled())
+ m_gdb_comm.StartReadThread();
+
// We always seem to be able to open a connection to a local port
// so we need to make sure we can then send data to it. If we can't
// then we aren't actually connected to anything, so try and do the
@@ -1027,12 +1174,23 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
error.SetErrorString("not connected to remote gdb server");
return error;
}
+
+ // Send $QNonStop:1 packet on startup if required
+ if (GetTarget().GetNonStopModeEnabled())
+ GetTarget().SetNonStopModeEnabled (m_gdb_comm.SetNonStopMode(true));
+
+ m_gdb_comm.GetEchoSupported ();
m_gdb_comm.GetThreadSuffixSupported ();
m_gdb_comm.GetListThreadsInStopReplySupported ();
m_gdb_comm.GetHostInfo ();
m_gdb_comm.GetVContSupported ('c');
m_gdb_comm.GetVAttachOrWaitSupported();
-
+
+ // Ask the remote server for the default thread id
+ if (GetTarget().GetNonStopModeEnabled())
+ m_gdb_comm.GetDefaultThreadId(m_initial_tid);
+
+
size_t num_cmds = GetExtraStartupCommands().GetArgumentCount();
for (size_t idx = 0; idx < num_cmds; idx++)
{
@@ -1081,7 +1239,7 @@ ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch)
if (process_arch.IsValid())
{
- ArchSpec &target_arch = GetTarget().GetArchitecture();
+ const ArchSpec &target_arch = GetTarget().GetArchitecture();
if (target_arch.IsValid())
{
if (log)
@@ -1111,20 +1269,23 @@ ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch)
{
// Fill in what is missing in the triple
const llvm::Triple &remote_triple = process_arch.GetTriple();
- llvm::Triple &target_triple = target_arch.GetTriple();
- if (target_triple.getVendorName().size() == 0)
+ llvm::Triple new_target_triple = target_arch.GetTriple();
+ if (new_target_triple.getVendorName().size() == 0)
{
- target_triple.setVendor (remote_triple.getVendor());
+ new_target_triple.setVendor (remote_triple.getVendor());
- if (target_triple.getOSName().size() == 0)
+ if (new_target_triple.getOSName().size() == 0)
{
- target_triple.setOS (remote_triple.getOS());
+ new_target_triple.setOS (remote_triple.getOS());
- if (target_triple.getEnvironmentName().size() == 0)
- target_triple.setEnvironment (remote_triple.getEnvironment());
+ if (new_target_triple.getEnvironmentName().size() == 0)
+ new_target_triple.setEnvironment (remote_triple.getEnvironment());
}
- }
+ ArchSpec new_target_arch = target_arch;
+ new_target_arch.SetTriple(new_target_triple);
+ GetTarget().SetArchitecture(new_target_arch);
+ }
}
if (log)
@@ -1151,13 +1312,6 @@ ProcessGDBRemote::DidLaunch ()
}
Error
-ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid)
-{
- ProcessAttachInfo attach_info;
- return DoAttachToProcessWithID(attach_pid, attach_info);
-}
-
-Error
ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info)
{
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
@@ -1255,12 +1409,11 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const Pro
return error;
}
-
-bool
-ProcessGDBRemote::SetExitStatus (int exit_status, const char *cstr)
+void
+ProcessGDBRemote::DidExit ()
{
+ // When we exit, disconnect from the GDB server communications
m_gdb_comm.Disconnect();
- return Process::SetExitStatus (exit_status, cstr);
}
void
@@ -1301,11 +1454,12 @@ ProcessGDBRemote::DoResume ()
bool continue_packet_error = false;
if (m_gdb_comm.HasAnyVContSupport ())
{
- if (m_continue_c_tids.size() == num_threads ||
+ if (!GetTarget().GetNonStopModeEnabled() &&
+ (m_continue_c_tids.size() == num_threads ||
(m_continue_c_tids.empty() &&
m_continue_C_tids.empty() &&
m_continue_s_tids.empty() &&
- m_continue_S_tids.empty()))
+ m_continue_S_tids.empty())))
{
// All threads are continuing, just send a "c" packet
continue_packet.PutCString ("c");
@@ -1443,7 +1597,18 @@ ProcessGDBRemote::DoResume ()
{
// All threads are resuming...
m_gdb_comm.SetCurrentThreadForRun (-1);
- continue_packet.PutChar ('s');
+
+ // If in Non-Stop-Mode use vCont when stepping
+ if (GetTarget().GetNonStopModeEnabled())
+ {
+ if (m_gdb_comm.GetVContSupported('s'))
+ continue_packet.PutCString("vCont;s");
+ else
+ continue_packet.PutChar('s');
+ }
+ else
+ continue_packet.PutChar('s');
+
continue_packet_error = false;
}
else if (num_continue_c_tids == 0 &&
@@ -1533,16 +1698,112 @@ ProcessGDBRemote::DoResume ()
}
void
+ProcessGDBRemote::HandleStopReplySequence ()
+{
+ while(true)
+ {
+ // Send vStopped
+ StringExtractorGDBRemote response;
+ m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response, false);
+
+ // OK represents end of signal list
+ if (response.IsOKResponse())
+ break;
+
+ // If not OK or a normal packet we have a problem
+ if (!response.IsNormalResponse())
+ break;
+
+ SetLastStopPacket(response);
+ }
+}
+
+void
ProcessGDBRemote::ClearThreadIDList ()
{
Mutex::Locker locker(m_thread_list_real.GetMutex());
m_thread_ids.clear();
}
+size_t
+ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue (std::string &value)
+{
+ m_thread_ids.clear();
+ size_t comma_pos;
+ lldb::tid_t tid;
+ while ((comma_pos = value.find(',')) != std::string::npos)
+ {
+ value[comma_pos] = '\0';
+ // thread in big endian hex
+ tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ m_thread_ids.push_back (tid);
+ value.erase(0, comma_pos + 1);
+ }
+ tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ m_thread_ids.push_back (tid);
+ return m_thread_ids.size();
+}
+
bool
ProcessGDBRemote::UpdateThreadIDList ()
{
Mutex::Locker locker(m_thread_list_real.GetMutex());
+
+ if (m_threads_info_sp)
+ {
+ // If we have the JSON threads info, we can get the thread list from that
+ StructuredData::Array *thread_infos = m_threads_info_sp->GetAsArray();
+ if (thread_infos && thread_infos->GetSize() > 0)
+ {
+ m_thread_ids.clear();
+ thread_infos->ForEach([this](StructuredData::Object* object) -> bool {
+ StructuredData::Dictionary *thread_dict = object->GetAsDictionary();
+ if (thread_dict)
+ {
+ // Set the thread stop info from the JSON dictionary
+ SetThreadStopInfo (thread_dict);
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid))
+ m_thread_ids.push_back(tid);
+ }
+ return true; // Keep iterating through all thread_info objects
+ });
+ }
+ if (!m_thread_ids.empty())
+ return true;
+ }
+ else
+ {
+ // See if we can get the thread IDs from the current stop reply packets
+ // that might contain a "threads" key/value pair
+
+ // Lock the thread stack while we access it
+ Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex);
+ // Get the number of stop packets on the stack
+ int nItems = m_stop_packet_stack.size();
+ // Iterate over them
+ for (int i = 0; i < nItems; i++)
+ {
+ // Get the thread stop info
+ StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i];
+ const std::string &stop_info_str = stop_info.GetStringRef();
+ const size_t threads_pos = stop_info_str.find(";threads:");
+ if (threads_pos != std::string::npos)
+ {
+ const size_t start = threads_pos + strlen(";threads:");
+ const size_t end = stop_info_str.find(';', start);
+ if (end != std::string::npos)
+ {
+ std::string value = stop_info_str.substr(start, end - start);
+ if (UpdateThreadIDsFromStopReplyThreadsValue(value))
+ return true;
+ }
+ }
+ }
+ }
+
bool sequence_mutex_unavailable = false;
m_gdb_comm.GetCurrentThreadIDs (m_thread_ids, sequence_mutex_unavailable);
if (sequence_mutex_unavailable)
@@ -1614,6 +1875,423 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new
return true;
}
+bool
+ProcessGDBRemote::CalculateThreadStopInfo (ThreadGDBRemote *thread)
+{
+ // See if we got thread stop infos for all threads via the "jThreadsInfo" packet
+ if (m_threads_info_sp)
+ {
+ StructuredData::Array *thread_infos = m_threads_info_sp->GetAsArray();
+ if (thread_infos)
+ {
+ lldb::tid_t tid;
+ const size_t n = thread_infos->GetSize();
+ for (size_t i=0; i<n; ++i)
+ {
+ StructuredData::Dictionary *thread_dict = thread_infos->GetItemAtIndex(i)->GetAsDictionary();
+ if (thread_dict)
+ {
+ if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid, LLDB_INVALID_THREAD_ID))
+ {
+ if (tid == thread->GetID())
+ return SetThreadStopInfo(thread_dict);
+ }
+ }
+ }
+ }
+ }
+
+ // Fall back to using the qThreadStopInfo packet
+ StringExtractorGDBRemote stop_packet;
+ if (GetGDBRemote().GetThreadStopInfo(thread->GetProtocolID(), stop_packet))
+ return SetThreadStopInfo (stop_packet) == eStateStopped;
+ return false;
+}
+
+
+ThreadSP
+ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid,
+ ExpeditedRegisterMap &expedited_register_map,
+ uint8_t signo,
+ const std::string &thread_name,
+ const std::string &reason,
+ const std::string &description,
+ uint32_t exc_type,
+ const std::vector<addr_t> &exc_data,
+ addr_t thread_dispatch_qaddr,
+ bool queue_vars_valid, // Set to true if queue_name, queue_kind and queue_serial are valid
+ std::string &queue_name,
+ QueueKind queue_kind,
+ uint64_t queue_serial)
+{
+ ThreadSP thread_sp;
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ // Scope for "locker" below
+ {
+ // m_thread_list_real does have its own mutex, but we need to
+ // hold onto the mutex between the call to m_thread_list_real.FindThreadByID(...)
+ // and the m_thread_list_real.AddThread(...) so it doesn't change on us
+ Mutex::Locker locker (m_thread_list_real.GetMutex ());
+ thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false);
+
+ if (!thread_sp)
+ {
+ // Create the thread if we need to
+ thread_sp.reset (new ThreadGDBRemote (*this, tid));
+ m_thread_list_real.AddThread(thread_sp);
+ }
+ }
+
+ if (thread_sp)
+ {
+ ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get());
+ gdb_thread->GetRegisterContext()->InvalidateIfNeeded(true);
+
+ for (const auto &pair : expedited_register_map)
+ {
+ StringExtractor reg_value_extractor;
+ reg_value_extractor.GetStringRef() = pair.second;
+ gdb_thread->PrivateSetRegisterValue (pair.first, reg_value_extractor);
+ }
+
+ // Clear the stop info just in case we don't set it to anything
+ thread_sp->SetStopInfo (StopInfoSP());
+ thread_sp->SetName (thread_name.empty() ? NULL : thread_name.c_str());
+
+ gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr);
+ // Check if the GDB server was able to provide the queue name, kind and serial number
+ if (queue_vars_valid)
+ gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial);
+ else
+ gdb_thread->ClearQueueInfo();
+
+
+ if (exc_type != 0)
+ {
+ const size_t exc_data_size = exc_data.size();
+
+ thread_sp->SetStopInfo (StopInfoMachException::CreateStopReasonWithMachException (*thread_sp,
+ exc_type,
+ exc_data_size,
+ exc_data_size >= 1 ? exc_data[0] : 0,
+ exc_data_size >= 2 ? exc_data[1] : 0,
+ exc_data_size >= 3 ? exc_data[2] : 0));
+ }
+ else
+ {
+ bool handled = false;
+ bool did_exec = false;
+ if (!reason.empty())
+ {
+ if (reason.compare("trace") == 0)
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
+ handled = true;
+ }
+ else if (reason.compare("breakpoint") == 0)
+ {
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC();
+ 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,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ handled = true;
+ if (bp_site_sp->ValidForThisThread (thread_sp.get()))
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
+ }
+ else
+ {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo (invalid_stop_info_sp);
+ }
+ }
+ }
+ else if (reason.compare("trap") == 0)
+ {
+ // Let the trap just use the standard signal stop reason below...
+ }
+ else if (reason.compare("watchpoint") == 0)
+ {
+ StringExtractor desc_extractor(description.c_str());
+ addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
+ uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32);
+ watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
+ if (wp_addr != LLDB_INVALID_ADDRESS)
+ {
+ WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
+ if (wp_sp)
+ {
+ wp_sp->SetHardwareIndex(wp_index);
+ watch_id = wp_sp->GetID();
+ }
+ }
+ if (watch_id == LLDB_INVALID_WATCH_ID)
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_WATCHPOINTS));
+ if (log) log->Printf ("failed to find watchpoint");
+ }
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id));
+ handled = true;
+ }
+ else if (reason.compare("exception") == 0)
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException(*thread_sp, description.c_str()));
+ handled = true;
+ }
+ else if (reason.compare("exec") == 0)
+ {
+ did_exec = true;
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithExec(*thread_sp));
+ handled = true;
+ }
+ }
+
+ if (!handled && signo && did_exec == false)
+ {
+ if (signo == SIGTRAP)
+ {
+ // Currently we are going to assume SIGTRAP means we are either
+ // hitting a breakpoint or hardware single stepping.
+ 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,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site_sp->ValidForThisThread (thread_sp.get()))
+ {
+ if(m_breakpoint_pc_offset != 0)
+ thread_sp->GetRegisterContext()->SetPC(pc);
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
+ }
+ else
+ {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo (invalid_stop_info_sp);
+ }
+ }
+ else
+ {
+ // If we were stepping then assume the stop was the result of the trace. If we were
+ // not stepping then report the SIGTRAP.
+ // FIXME: We are still missing the case where we single step over a trap instruction.
+ if (thread_sp->GetTemporaryResumeState() == eStateStepping)
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
+ else
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo, description.c_str()));
+ }
+ }
+ if (!handled)
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo, description.c_str()));
+ }
+
+ if (!description.empty())
+ {
+ lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
+ if (stop_info_sp)
+ {
+ const char *stop_info_desc = stop_info_sp->GetDescription();
+ if (!stop_info_desc || !stop_info_desc[0])
+ stop_info_sp->SetDescription (description.c_str());
+ }
+ else
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str()));
+ }
+ }
+ }
+ }
+ }
+ return thread_sp;
+}
+
+StateType
+ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict)
+{
+ static ConstString g_key_tid("tid");
+ static ConstString g_key_name("name");
+ static ConstString g_key_reason("reason");
+ static ConstString g_key_metype("metype");
+ static ConstString g_key_medata("medata");
+ static ConstString g_key_qaddr("qaddr");
+ static ConstString g_key_queue_name("qname");
+ static ConstString g_key_queue_kind("qkind");
+ static ConstString g_key_queue_serial("qserial");
+ static ConstString g_key_registers("registers");
+ static ConstString g_key_memory("memory");
+ static ConstString g_key_address("address");
+ static ConstString g_key_bytes("bytes");
+ static ConstString g_key_description("description");
+
+ // Stop with signal and thread info
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ uint8_t signo = 0;
+ std::string value;
+ std::string thread_name;
+ std::string reason;
+ std::string description;
+ uint32_t exc_type = 0;
+ std::vector<addr_t> exc_data;
+ addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
+ ExpeditedRegisterMap expedited_register_map;
+ bool queue_vars_valid = false;
+ std::string queue_name;
+ QueueKind queue_kind = eQueueKindUnknown;
+ uint64_t queue_serial = 0;
+ // Iterate through all of the thread dictionary key/value pairs from the structured data dictionary
+
+ thread_dict->ForEach([this,
+ &tid,
+ &expedited_register_map,
+ &thread_name,
+ &signo,
+ &reason,
+ &description,
+ &exc_type,
+ &exc_data,
+ &thread_dispatch_qaddr,
+ &queue_vars_valid,
+ &queue_name,
+ &queue_kind,
+ &queue_serial]
+ (ConstString key, StructuredData::Object* object) -> bool
+ {
+ if (key == g_key_tid)
+ {
+ // thread in big endian hex
+ tid = object->GetIntegerValue(LLDB_INVALID_THREAD_ID);
+ }
+ else if (key == g_key_metype)
+ {
+ // exception type in big endian hex
+ exc_type = object->GetIntegerValue(0);
+ }
+ else if (key == g_key_medata)
+ {
+ // exception data in big endian hex
+ StructuredData::Array *array = object->GetAsArray();
+ if (array)
+ {
+ array->ForEach([&exc_data](StructuredData::Object* object) -> bool {
+ exc_data.push_back(object->GetIntegerValue());
+ return true; // Keep iterating through all array items
+ });
+ }
+ }
+ else if (key == g_key_name)
+ {
+ thread_name = std::move(object->GetStringValue());
+ }
+ else if (key == g_key_qaddr)
+ {
+ thread_dispatch_qaddr = object->GetIntegerValue(LLDB_INVALID_ADDRESS);
+ }
+ else if (key == g_key_queue_name)
+ {
+ queue_vars_valid = true;
+ queue_name = std::move(object->GetStringValue());
+ }
+ else if (key == g_key_queue_kind)
+ {
+ std::string queue_kind_str = object->GetStringValue();
+ if (queue_kind_str == "serial")
+ {
+ queue_vars_valid = true;
+ queue_kind = eQueueKindSerial;
+ }
+ else if (queue_kind_str == "concurrent")
+ {
+ queue_vars_valid = true;
+ queue_kind = eQueueKindConcurrent;
+ }
+ }
+ else if (key == g_key_queue_serial)
+ {
+ queue_serial = object->GetIntegerValue(0);
+ if (queue_serial != 0)
+ queue_vars_valid = true;
+ }
+ else if (key == g_key_reason)
+ {
+ reason = std::move(object->GetStringValue());
+ }
+ else if (key == g_key_description)
+ {
+ description = std::move(object->GetStringValue());
+ }
+ else if (key == g_key_registers)
+ {
+ StructuredData::Dictionary *registers_dict = object->GetAsDictionary();
+
+ if (registers_dict)
+ {
+ registers_dict->ForEach([&expedited_register_map](ConstString key, StructuredData::Object* object) -> bool {
+ const uint32_t reg = StringConvert::ToUInt32 (key.GetCString(), UINT32_MAX, 10);
+ if (reg != UINT32_MAX)
+ expedited_register_map[reg] = std::move(object->GetStringValue());
+ return true; // Keep iterating through all array items
+ });
+ }
+ }
+ else if (key == g_key_memory)
+ {
+ StructuredData::Array *array = object->GetAsArray();
+ if (array)
+ {
+ array->ForEach([this](StructuredData::Object* object) -> bool {
+ StructuredData::Dictionary *mem_cache_dict = object->GetAsDictionary();
+ if (mem_cache_dict)
+ {
+ lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS;
+ if (mem_cache_dict->GetValueForKeyAsInteger<lldb::addr_t>("address", mem_cache_addr))
+ {
+ if (mem_cache_addr != LLDB_INVALID_ADDRESS)
+ {
+ StringExtractor bytes;
+ if (mem_cache_dict->GetValueForKeyAsString("bytes", bytes.GetStringRef()))
+ {
+ bytes.SetFilePos(0);
+
+ const size_t byte_size = bytes.GetStringRef().size()/2;
+ DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0));
+ const size_t bytes_copied = bytes.GetHexBytes (data_buffer_sp->GetBytes(), byte_size, 0);
+ if (bytes_copied == byte_size)
+ m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp);
+ }
+ }
+ }
+ }
+ return true; // Keep iterating through all array items
+ });
+ }
+
+ }
+ return true; // Keep iterating through all dictionary key/value pairs
+ });
+
+ SetThreadStopInfo (tid,
+ expedited_register_map,
+ signo,
+ thread_name,
+ reason,
+ description,
+ exc_type,
+ exc_data,
+ thread_dispatch_qaddr,
+ queue_vars_valid,
+ queue_name,
+ queue_kind,
+ queue_serial);
+
+ return eStateExited;
+}
StateType
ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
@@ -1644,8 +2322,9 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
BuildDynamicRegisterInfo (true);
}
// Stop with signal and thread info
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
const uint8_t signo = stop_packet.GetHexU8();
- std::string name;
+ std::string key;
std::string value;
std::string thread_name;
std::string reason;
@@ -1653,48 +2332,29 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
uint32_t exc_type = 0;
std::vector<addr_t> exc_data;
addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
- ThreadSP thread_sp;
- ThreadGDBRemote *gdb_thread = NULL;
-
- while (stop_packet.GetNameColonValue(name, value))
+ bool queue_vars_valid = false; // says if locals below that start with "queue_" are valid
+ std::string queue_name;
+ QueueKind queue_kind = eQueueKindUnknown;
+ uint64_t queue_serial = 0;
+ ExpeditedRegisterMap expedited_register_map;
+ while (stop_packet.GetNameColonValue(key, value))
{
- if (name.compare("metype") == 0)
+ if (key.compare("metype") == 0)
{
// exception type in big endian hex
exc_type = StringConvert::ToUInt32 (value.c_str(), 0, 16);
}
- else if (name.compare("medata") == 0)
+ else if (key.compare("medata") == 0)
{
// exception data in big endian hex
exc_data.push_back(StringConvert::ToUInt64 (value.c_str(), 0, 16));
}
- else if (name.compare("thread") == 0)
+ else if (key.compare("thread") == 0)
{
// thread in big endian hex
- lldb::tid_t tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
- // m_thread_list_real does have its own mutex, but we need to
- // hold onto the mutex between the call to m_thread_list_real.FindThreadByID(...)
- // and the m_thread_list_real.AddThread(...) so it doesn't change on us
- Mutex::Locker locker (m_thread_list_real.GetMutex ());
- thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false);
-
- if (!thread_sp)
- {
- // Create the thread if we need to
- thread_sp.reset (new ThreadGDBRemote (*this, tid));
- Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD));
- if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
- log->Printf ("ProcessGDBRemote::%s Adding new thread: %p for thread ID: 0x%" PRIx64 ".\n",
- __FUNCTION__,
- static_cast<void*>(thread_sp.get()),
- thread_sp->GetID());
-
- m_thread_list_real.AddThread(thread_sp);
- }
- gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get());
-
+ tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
}
- else if (name.compare("threads") == 0)
+ else if (key.compare("threads") == 0)
{
Mutex::Locker locker(m_thread_list_real.GetMutex());
m_thread_ids.clear();
@@ -1716,7 +2376,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
if (tid != LLDB_INVALID_THREAD_ID)
m_thread_ids.push_back (tid);
}
- else if (name.compare("hexname") == 0)
+ else if (key.compare("hexname") == 0)
{
StringExtractor name_extractor;
// Swap "value" over into "name_extractor"
@@ -1725,19 +2385,48 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
name_extractor.GetHexByteString (value);
thread_name.swap (value);
}
- else if (name.compare("name") == 0)
+ else if (key.compare("name") == 0)
{
thread_name.swap (value);
}
- else if (name.compare("qaddr") == 0)
+ else if (key.compare("qaddr") == 0)
{
thread_dispatch_qaddr = StringConvert::ToUInt64 (value.c_str(), 0, 16);
}
- else if (name.compare("reason") == 0)
+ else if (key.compare("qname") == 0)
+ {
+ queue_vars_valid = true;
+ StringExtractor name_extractor;
+ // Swap "value" over into "name_extractor"
+ name_extractor.GetStringRef().swap(value);
+ // Now convert the HEX bytes into a string value
+ name_extractor.GetHexByteString (value);
+ queue_name.swap (value);
+ }
+ else if (key.compare("qkind") == 0)
+ {
+ if (value == "serial")
+ {
+ queue_vars_valid = true;
+ queue_kind = eQueueKindSerial;
+ }
+ else if (value == "concurrent")
+ {
+ queue_vars_valid = true;
+ queue_kind = eQueueKindConcurrent;
+ }
+ }
+ else if (key.compare("qserial") == 0)
+ {
+ queue_serial = StringConvert::ToUInt64 (value.c_str(), 0, 0);
+ if (queue_serial != 0)
+ queue_vars_valid = true;
+ }
+ else if (key.compare("reason") == 0)
{
reason.swap(value);
}
- else if (name.compare("description") == 0)
+ else if (key.compare("description") == 0)
{
StringExtractor desc_extractor;
// Swap "value" over into "name_extractor"
@@ -1746,34 +2435,61 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
desc_extractor.GetHexByteString (value);
description.swap(value);
}
- else if (name.size() == 2 && ::isxdigit(name[0]) && ::isxdigit(name[1]))
+ else if (key.compare("memory") == 0)
{
- // We have a register number that contains an expedited
- // register value. Lets supply this register to our thread
- // so it won't have to go and read it.
- if (gdb_thread)
+ // Expedited memory. GDB servers can choose to send back expedited memory
+ // that can populate the L1 memory cache in the process so that things like
+ // the frame pointer backchain can be expedited. This will help stack
+ // backtracing be more efficient by not having to send as many memory read
+ // requests down the remote GDB server.
+
+ // Key/value pair format: memory:<addr>=<bytes>;
+ // <addr> is a number whose base will be interpreted by the prefix:
+ // "0x[0-9a-fA-F]+" for hex
+ // "0[0-7]+" for octal
+ // "[1-9]+" for decimal
+ // <bytes> is native endian ASCII hex bytes just like the register values
+ llvm::StringRef value_ref(value);
+ std::pair<llvm::StringRef, llvm::StringRef> pair;
+ pair = value_ref.split('=');
+ if (!pair.first.empty() && !pair.second.empty())
{
- uint32_t reg = StringConvert::ToUInt32 (name.c_str(), UINT32_MAX, 16);
-
- if (reg != UINT32_MAX)
+ std::string addr_str(pair.first.str());
+ const lldb::addr_t mem_cache_addr = StringConvert::ToUInt64(addr_str.c_str(), LLDB_INVALID_ADDRESS, 0);
+ if (mem_cache_addr != LLDB_INVALID_ADDRESS)
{
- StringExtractor reg_value_extractor;
- // Swap "value" over into "reg_value_extractor"
- reg_value_extractor.GetStringRef().swap(value);
- if (!gdb_thread->PrivateSetRegisterValue (reg, reg_value_extractor))
- {
- Host::SetCrashDescriptionWithFormat("Setting thread register '%s' (decoded to %u (0x%x)) with value '%s' for stop packet: '%s'",
- name.c_str(),
- reg,
- reg,
- reg_value_extractor.GetStringRef().c_str(),
- stop_packet.GetStringRef().c_str());
- }
+ StringExtractor bytes;
+ bytes.GetStringRef() = std::move(pair.second.str());
+ const size_t byte_size = bytes.GetStringRef().size()/2;
+ DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0));
+ const size_t bytes_copied = bytes.GetHexBytes (data_buffer_sp->GetBytes(), byte_size, 0);
+ if (bytes_copied == byte_size)
+ m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp);
}
}
}
+ else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1]))
+ {
+ uint32_t reg = StringConvert::ToUInt32 (key.c_str(), UINT32_MAX, 16);
+ if (reg != UINT32_MAX)
+ expedited_register_map[reg] = std::move(value);
+ }
}
+ ThreadSP thread_sp = SetThreadStopInfo (tid,
+ expedited_register_map,
+ signo,
+ thread_name,
+ reason,
+ description,
+ exc_type,
+ exc_data,
+ thread_dispatch_qaddr,
+ queue_vars_valid,
+ queue_name,
+ queue_kind,
+ queue_serial);
+
// If the response is old style 'S' packet which does not provide us with thread information
// then update the thread list and choose the first one.
if (!thread_sp)
@@ -1784,157 +2500,9 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
{
Mutex::Locker locker (m_thread_list_real.GetMutex ());
thread_sp = m_thread_list_real.FindThreadByProtocolID (m_thread_ids.front (), false);
- if (thread_sp)
- gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get ());
}
}
- if (thread_sp)
- {
- // Clear the stop info just in case we don't set it to anything
- thread_sp->SetStopInfo (StopInfoSP());
-
- gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr);
- gdb_thread->SetName (thread_name.empty() ? NULL : thread_name.c_str());
- if (exc_type != 0)
- {
- const size_t exc_data_size = exc_data.size();
-
- thread_sp->SetStopInfo (StopInfoMachException::CreateStopReasonWithMachException (*thread_sp,
- exc_type,
- exc_data_size,
- exc_data_size >= 1 ? exc_data[0] : 0,
- exc_data_size >= 2 ? exc_data[1] : 0,
- exc_data_size >= 3 ? exc_data[2] : 0));
- }
- else
- {
- bool handled = false;
- bool did_exec = false;
- if (!reason.empty())
- {
- if (reason.compare("trace") == 0)
- {
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
- handled = true;
- }
- else if (reason.compare("breakpoint") == 0)
- {
- addr_t pc = thread_sp->GetRegisterContext()->GetPC();
- 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,
- // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
- // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
- handled = true;
- if (bp_site_sp->ValidForThisThread (thread_sp.get()))
- {
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
- }
- else
- {
- StopInfoSP invalid_stop_info_sp;
- thread_sp->SetStopInfo (invalid_stop_info_sp);
- }
- }
- }
- else if (reason.compare("trap") == 0)
- {
- // Let the trap just use the standard signal stop reason below...
- }
- else if (reason.compare("watchpoint") == 0)
- {
- StringExtractor desc_extractor(description.c_str());
- addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
- uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32);
- watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
- if (wp_addr != LLDB_INVALID_ADDRESS)
- {
- WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
- if (wp_sp)
- {
- wp_sp->SetHardwareIndex(wp_index);
- watch_id = wp_sp->GetID();
- }
- }
- if (watch_id == LLDB_INVALID_WATCH_ID)
- {
- Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_WATCHPOINTS));
- if (log) log->Printf ("failed to find watchpoint");
- }
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id));
- handled = true;
- }
- else if (reason.compare("exception") == 0)
- {
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException(*thread_sp, description.c_str()));
- handled = true;
- }
- else if (reason.compare("exec") == 0)
- {
- did_exec = true;
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithExec(*thread_sp));
- handled = true;
- }
- }
-
- if (!handled && signo && did_exec == false)
- {
- if (signo == SIGTRAP)
- {
- // Currently we are going to assume SIGTRAP means we are either
- // hitting a breakpoint or hardware single stepping.
- 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,
- // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
- // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
- if (bp_site_sp->ValidForThisThread (thread_sp.get()))
- {
- if(m_breakpoint_pc_offset != 0)
- thread_sp->GetRegisterContext()->SetPC(pc);
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
- }
- else
- {
- StopInfoSP invalid_stop_info_sp;
- thread_sp->SetStopInfo (invalid_stop_info_sp);
- }
- }
- else
- {
- // If we were stepping then assume the stop was the result of the trace. If we were
- // not stepping then report the SIGTRAP.
- // FIXME: We are still missing the case where we single step over a trap instruction.
- if (thread_sp->GetTemporaryResumeState() == eStateStepping)
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
- else
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo));
- }
- }
- if (!handled)
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo));
- }
-
- if (!description.empty())
- {
- lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
- if (stop_info_sp)
- {
- stop_info_sp->SetDescription (description.c_str());
- }
- else
- {
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str()));
- }
- }
- }
- }
return eStateStopped;
}
break;
@@ -1958,7 +2526,25 @@ ProcessGDBRemote::RefreshStateAfterStop ()
// Set the thread stop info. It might have a "threads" key whose value is
// a list of all thread IDs in the current process, so m_thread_ids might
// get set.
- SetThreadStopInfo (m_last_stop_packet);
+
+ // Scope for the lock
+ {
+ // Lock the thread stack while we access it
+ Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex);
+ // Get the number of stop packets on the stack
+ int nItems = m_stop_packet_stack.size();
+ // Iterate over them
+ for (int i = 0; i < nItems; i++)
+ {
+ // Get the thread stop info
+ StringExtractorGDBRemote stop_info = m_stop_packet_stack[i];
+ // Process thread stop info
+ SetThreadStopInfo(stop_info);
+ }
+ // Clear the thread stop stack
+ m_stop_packet_stack.clear();
+ }
+
// Check to see if SetThreadStopInfo() filled in m_thread_ids?
if (m_thread_ids.empty())
{
@@ -1966,6 +2552,18 @@ ProcessGDBRemote::RefreshStateAfterStop ()
UpdateThreadIDList();
}
+ // If we have queried for a default thread id
+ if (m_initial_tid != LLDB_INVALID_THREAD_ID)
+ {
+ m_thread_list.SetSelectedThreadByID(m_initial_tid);
+ m_initial_tid = LLDB_INVALID_THREAD_ID;
+ }
+
+ // Fetch the threads via an efficient packet that gets stop infos for all threads
+ // only if we have more than one thread
+ if (m_thread_ids.size() > 1)
+ m_threads_info_sp = m_gdb_comm.GetThreadsInfo();
+
// Let all threads recover from stopping and do any clean up based
// on the previous thread state (if any).
m_thread_list_real.RefreshStateAfterStop();
@@ -2138,7 +2736,7 @@ ProcessGDBRemote::DoDestroy ()
}
}
Resume ();
- return Destroy();
+ return Destroy(false);
}
}
}
@@ -2152,10 +2750,9 @@ ProcessGDBRemote::DoDestroy ()
{
if (m_public_state.GetValue() != eStateAttaching)
{
-
StringExtractorGDBRemote response;
bool send_async = true;
- const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (3);
+ GDBRemoteCommunication::ScopedTimeout (m_gdb_comm, 3);
if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async) == GDBRemoteCommunication::PacketResult::Success)
{
@@ -2199,8 +2796,6 @@ ProcessGDBRemote::DoDestroy ()
log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet");
exit_string.assign("failed to send the k packet");
}
-
- m_gdb_comm.SetPacketTimeout(old_packet_timeout);
}
else
{
@@ -2226,7 +2821,6 @@ ProcessGDBRemote::DoDestroy ()
void
ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response)
{
- lldb_private::Mutex::Locker locker (m_last_stop_packet_mutex);
const bool did_exec = response.GetStringRef().find(";reason:exec;") != std::string::npos;
if (did_exec)
{
@@ -2237,9 +2831,18 @@ ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response)
m_thread_list_real.Clear();
m_thread_list.Clear();
BuildDynamicRegisterInfo (true);
- m_gdb_comm.ResetDiscoverableSettings();
+ m_gdb_comm.ResetDiscoverableSettings (did_exec);
+ }
+
+ // Scope the lock
+ {
+ // Lock the thread stack while we access it
+ Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex);
+ // Add this stop packet to the stop packet stack
+ // This stack will get popped and examined when we switch to the
+ // Stopped state
+ m_stop_packet_stack.push_back(response);
}
- m_last_stop_packet = response;
}
@@ -2256,7 +2859,18 @@ ProcessGDBRemote::IsAlive ()
addr_t
ProcessGDBRemote::GetImageInfoAddress()
{
- return m_gdb_comm.GetShlibInfoAddr();
+ // request the link map address via the $qShlibInfoAddr packet
+ lldb::addr_t addr = m_gdb_comm.GetShlibInfoAddr();
+
+ // the loaded module list can also provides a link map address
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ GDBLoadedModuleInfoList list;
+ if (GetLoadedModuleList (list).Success())
+ addr = list.m_link_map;
+ }
+
+ return addr;
}
//------------------------------------------------------------------
@@ -2366,7 +2980,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));
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_EXPRESSIONS));
addr_t allocated_addr = LLDB_INVALID_ADDRESS;
LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
@@ -2478,7 +3092,7 @@ ProcessGDBRemote::PutSTDIN (const char *src, size_t src_len, Error &error)
ConnectionStatus status;
m_stdio_communication.Write(src, src_len, status, NULL);
}
- else if (!m_stdio_disable)
+ else if (m_stdin_forward)
{
m_gdb_comm.SendStdinNotification(src, src_len);
}
@@ -2945,28 +3559,19 @@ ProcessGDBRemote::KillDebugserverProcess ()
void
ProcessGDBRemote::Initialize()
{
- static bool g_initialized = false;
+ static std::once_flag g_once_flag;
- if (g_initialized == false)
+ std::call_once(g_once_flag, []()
{
- g_initialized = true;
PluginManager::RegisterPlugin (GetPluginNameStatic(),
GetPluginDescriptionStatic(),
CreateInstance,
DebuggerInitialize);
-
- Log::Callbacks log_callbacks = {
- ProcessGDBRemoteLog::DisableLog,
- ProcessGDBRemoteLog::EnableLog,
- ProcessGDBRemoteLog::ListLogCategories
- };
-
- Log::RegisterLogChannel (ProcessGDBRemote::GetPluginNameStatic(), log_callbacks);
- }
+ });
}
void
-ProcessGDBRemote::DebuggerInitialize (lldb_private::Debugger &debugger)
+ProcessGDBRemote::DebuggerInitialize (Debugger &debugger)
{
if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName()))
{
@@ -3018,11 +3623,40 @@ ProcessGDBRemote::StopAsyncThread ()
// Stop the stdio thread
m_async_thread.Join(nullptr);
+ m_async_thread.Reset();
}
else if (log)
log->Printf("ProcessGDBRemote::%s () - Called when Async thread was not running.", __FUNCTION__);
}
+bool
+ProcessGDBRemote::HandleNotifyPacket (StringExtractorGDBRemote &packet)
+{
+ // get the packet at a string
+ const std::string &pkt = packet.GetStringRef();
+ // skip %stop:
+ StringExtractorGDBRemote stop_info(pkt.c_str() + 5);
+
+ // pass as a thread stop info packet
+ SetLastStopPacket(stop_info);
+
+ // check for more stop reasons
+ HandleStopReplySequence();
+
+ // if the process is stopped then we need to fake a resume
+ // so that we can stop properly with the new break. This
+ // is possible due to SetPrivateState() broadcasting the
+ // state change as a side effect.
+ if (GetPrivateState() == lldb::StateType::eStateStopped)
+ {
+ SetPrivateState(lldb::StateType::eStateRunning);
+ }
+
+ // since we have some stopped packets we can halt the process
+ SetPrivateState(lldb::StateType::eStateStopped);
+
+ return true;
+}
thread_result_t
ProcessGDBRemote::AsyncThread (void *arg)
@@ -3040,8 +3674,9 @@ ProcessGDBRemote::AsyncThread (void *arg)
if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask)
{
- listener.StartListeningForEvents (&process->m_gdb_comm, Communication::eBroadcastBitReadThreadDidExit);
-
+ listener.StartListeningForEvents (&process->m_gdb_comm, Communication::eBroadcastBitReadThreadDidExit |
+ GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify);
+
bool done = false;
while (!done)
{
@@ -3071,61 +3706,77 @@ ProcessGDBRemote::AsyncThread (void *arg)
if (::strstr (continue_cstr, "vAttach") == NULL)
process->SetPrivateState(eStateRunning);
StringExtractorGDBRemote response;
- StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response);
-
- // We need to immediately clear the thread ID list so we are sure to get a valid list of threads.
- // The thread ID list might be contained within the "response", or the stop reply packet that
- // caused the stop. So clear it now before we give the stop reply packet to the process
- // using the process->SetLastStopPacket()...
- process->ClearThreadIDList ();
-
- switch (stop_state)
+
+ // If in Non-Stop-Mode
+ if (process->GetTarget().GetNonStopModeEnabled())
{
- case eStateStopped:
- case eStateCrashed:
- case eStateSuspended:
- process->SetLastStopPacket (response);
- process->SetPrivateState (stop_state);
- break;
-
- case eStateExited:
+ // send the vCont packet
+ if (!process->GetGDBRemote().SendvContPacket(process, continue_cstr, continue_cstr_len, response))
+ {
+ // Something went wrong
+ done = true;
+ break;
+ }
+ }
+ // If in All-Stop-Mode
+ else
{
- process->SetLastStopPacket (response);
- process->ClearThreadIDList();
- response.SetFilePos(1);
-
- int exit_status = response.GetHexU8();
- const char *desc_cstr = NULL;
- StringExtractor extractor;
- std::string desc_string;
- if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';')
+ StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response);
+
+ // We need to immediately clear the thread ID list so we are sure to get a valid list of threads.
+ // The thread ID list might be contained within the "response", or the stop reply packet that
+ // caused the stop. So clear it now before we give the stop reply packet to the process
+ // using the process->SetLastStopPacket()...
+ process->ClearThreadIDList ();
+
+ switch (stop_state)
{
- std::string desc_token;
- while (response.GetNameColonValue (desc_token, desc_string))
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ process->SetLastStopPacket (response);
+ process->SetPrivateState (stop_state);
+ break;
+
+ case eStateExited:
+ {
+ process->SetLastStopPacket (response);
+ process->ClearThreadIDList();
+ response.SetFilePos(1);
+
+ int exit_status = response.GetHexU8();
+ const char *desc_cstr = NULL;
+ StringExtractor extractor;
+ std::string desc_string;
+ if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';')
{
- if (desc_token == "description")
+ std::string desc_token;
+ while (response.GetNameColonValue (desc_token, desc_string))
{
- extractor.GetStringRef().swap(desc_string);
- extractor.SetFilePos(0);
- extractor.GetHexByteString (desc_string);
- desc_cstr = desc_string.c_str();
+ 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;
}
- process->SetExitStatus(exit_status, desc_cstr);
- done = true;
- break;
- }
- case eStateInvalid:
- process->SetExitStatus(-1, "lost connection");
- break;
-
- default:
- process->SetPrivateState (stop_state);
- break;
- }
- }
- }
+ case eStateInvalid:
+ process->SetExitStatus(-1, "lost connection");
+ break;
+
+ default:
+ process->SetPrivateState (stop_state);
+ break;
+ } // switch(stop_state)
+ } // else // if in All-stop-mode
+ } // if (continue_packet)
+ } // case eBroadcastBitAysncContinue
break;
case eBroadcastBitAsyncThreadShouldExit:
@@ -3143,10 +3794,28 @@ ProcessGDBRemote::AsyncThread (void *arg)
}
else if (event_sp->BroadcasterIs (&process->m_gdb_comm))
{
- if (event_type & Communication::eBroadcastBitReadThreadDidExit)
+ switch (event_type)
{
- process->SetExitStatus (-1, "lost connection");
- done = true;
+ case Communication::eBroadcastBitReadThreadDidExit:
+ process->SetExitStatus (-1, "lost connection");
+ done = true;
+ break;
+
+ case GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify:
+ {
+ lldb_private::Event *event = event_sp.get();
+ const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event);
+ StringExtractorGDBRemote notify((const char*)continue_packet->GetBytes());
+ // Hand this over to the process to handle
+ process->HandleNotifyPacket(notify);
+ break;
+ }
+
+ default:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type);
+ done = true;
+ break;
}
}
}
@@ -3162,7 +3831,6 @@ ProcessGDBRemote::AsyncThread (void *arg)
if (log)
log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, arg, process->GetID());
- process->m_async_thread.Reset();
return NULL;
}
@@ -3185,13 +3853,13 @@ ProcessGDBRemote::AsyncThread (void *arg)
//
bool
ProcessGDBRemote::NewThreadNotifyBreakpointHit (void *baton,
- lldb_private::StoppointCallbackContext *context,
+ StoppointCallbackContext *context,
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id)
{
// I don't think I have to do anything here, just make sure I notice the new thread when it starts to
// run so I can stop it if that's what I want to do.
- Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log)
log->Printf("Hit New Thread Notification breakpoint.");
return false;
@@ -3201,7 +3869,7 @@ ProcessGDBRemote::NewThreadNotifyBreakpointHit (void *baton,
bool
ProcessGDBRemote::StartNoticingNewThreads()
{
- Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (m_thread_create_bp_sp)
{
if (log && log->GetVerbose())
@@ -3233,7 +3901,7 @@ ProcessGDBRemote::StartNoticingNewThreads()
bool
ProcessGDBRemote::StopNoticingNewThreads()
{
- Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log && log->GetVerbose())
log->Printf ("Disabling new thread notification breakpoint.");
@@ -3243,7 +3911,7 @@ ProcessGDBRemote::StopNoticingNewThreads()
return true;
}
-lldb_private::DynamicLoader *
+DynamicLoader *
ProcessGDBRemote::GetDynamicLoader ()
{
if (m_dyld_ap.get() == NULL)
@@ -3392,6 +4060,659 @@ ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified
}
}
+bool
+ProcessGDBRemote::GetModuleSpec(const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec)
+{
+ Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM);
+
+ if (!m_gdb_comm.GetModuleInfo (module_file_spec, arch, module_spec))
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s - failed to get module info for %s:%s",
+ __FUNCTION__, module_file_spec.GetPath ().c_str (),
+ arch.GetTriple ().getTriple ().c_str ());
+ return false;
+ }
+
+ if (log)
+ {
+ StreamString stream;
+ module_spec.Dump (stream);
+ log->Printf ("ProcessGDBRemote::%s - got module info for (%s:%s) : %s",
+ __FUNCTION__, module_file_spec.GetPath ().c_str (),
+ arch.GetTriple ().getTriple ().c_str (), stream.GetString ().c_str ());
+ }
+
+ return true;
+}
+
+namespace {
+
+typedef std::vector<std::string> stringVec;
+
+typedef std::vector<struct GdbServerRegisterInfo> GDBServerRegisterVec;
+struct RegisterSetInfo
+{
+ ConstString name;
+};
+
+typedef std::map<uint32_t, RegisterSetInfo> RegisterSetMap;
+
+struct GdbServerTargetInfo
+{
+ std::string arch;
+ std::string osabi;
+ stringVec includes;
+ RegisterSetMap reg_set_map;
+ XMLNode feature_node;
+};
+
+bool
+ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info)
+{
+ if (!feature_node)
+ return false;
+
+ uint32_t prev_reg_num = 0;
+ uint32_t reg_offset = 0;
+
+ feature_node.ForEachChildElementWithName("reg", [&target_info, &dyn_reg_info, &prev_reg_num, &reg_offset](const XMLNode &reg_node) -> bool {
+ std::string gdb_group;
+ std::string gdb_type;
+ ConstString reg_name;
+ ConstString alt_name;
+ ConstString set_name;
+ std::vector<uint32_t> value_regs;
+ std::vector<uint32_t> invalidate_regs;
+ bool encoding_set = false;
+ bool format_set = false;
+ RegisterInfo reg_info = { NULL, // Name
+ NULL, // Alt name
+ 0, // byte size
+ reg_offset, // offset
+ eEncodingUint, // encoding
+ eFormatHex, // formate
+ {
+ LLDB_INVALID_REGNUM, // GCC reg num
+ LLDB_INVALID_REGNUM, // DWARF reg num
+ LLDB_INVALID_REGNUM, // generic reg num
+ prev_reg_num, // GDB reg num
+ prev_reg_num // native register number
+ },
+ NULL,
+ NULL
+ };
+
+ reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, &reg_name, &alt_name, &set_name, &value_regs, &invalidate_regs, &encoding_set, &format_set, &reg_info, &prev_reg_num, &reg_offset](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
+ if (name == "name")
+ {
+ reg_name.SetString(value);
+ }
+ else if (name == "bitsize")
+ {
+ reg_info.byte_size = StringConvert::ToUInt32(value.data(), 0, 0) / CHAR_BIT;
+ }
+ else if (name == "type")
+ {
+ gdb_type = value.str();
+ }
+ else if (name == "group")
+ {
+ gdb_group = value.str();
+ }
+ else if (name == "regnum")
+ {
+ const uint32_t regnum = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
+ if (regnum != LLDB_INVALID_REGNUM)
+ {
+ reg_info.kinds[eRegisterKindGDB] = regnum;
+ reg_info.kinds[eRegisterKindLLDB] = regnum;
+ prev_reg_num = regnum;
+ }
+ }
+ else if (name == "offset")
+ {
+ reg_offset = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
+ }
+ else if (name == "altname")
+ {
+ alt_name.SetString(value);
+ }
+ else if (name == "encoding")
+ {
+ encoding_set = true;
+ reg_info.encoding = Args::StringToEncoding (value.data(), eEncodingUint);
+ }
+ else if (name == "format")
+ {
+ format_set = true;
+ Format format = eFormatInvalid;
+ if (Args::StringToFormat (value.data(), format, NULL).Success())
+ reg_info.format = format;
+ else if (value == "vector-sint8")
+ reg_info.format = eFormatVectorOfSInt8;
+ else if (value == "vector-uint8")
+ reg_info.format = eFormatVectorOfUInt8;
+ else if (value == "vector-sint16")
+ reg_info.format = eFormatVectorOfSInt16;
+ else if (value == "vector-uint16")
+ reg_info.format = eFormatVectorOfUInt16;
+ else if (value == "vector-sint32")
+ reg_info.format = eFormatVectorOfSInt32;
+ else if (value == "vector-uint32")
+ reg_info.format = eFormatVectorOfUInt32;
+ else if (value == "vector-float32")
+ reg_info.format = eFormatVectorOfFloat32;
+ else if (value == "vector-uint128")
+ reg_info.format = eFormatVectorOfUInt128;
+ }
+ else if (name == "group_id")
+ {
+ const uint32_t set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
+ RegisterSetMap::const_iterator pos = target_info.reg_set_map.find(set_id);
+ if (pos != target_info.reg_set_map.end())
+ set_name = pos->second.name;
+ }
+ else if (name == "gcc_regnum")
+ {
+ reg_info.kinds[eRegisterKindGCC] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name == "dwarf_regnum")
+ {
+ reg_info.kinds[eRegisterKindDWARF] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name == "generic")
+ {
+ reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister(value.data());
+ }
+ else if (name == "value_regnums")
+ {
+ SplitCommaSeparatedRegisterNumberString(value, value_regs, 0);
+ }
+ else if (name == "invalidate_regnums")
+ {
+ SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 0);
+ }
+ else
+ {
+ printf("unhandled attribute %s = %s\n", name.data(), value.data());
+ }
+ return true; // Keep iterating through all attributes
+ });
+
+ if (!gdb_type.empty() && !(encoding_set || format_set))
+ {
+ if (gdb_type.find("int") == 0)
+ {
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ }
+ else if (gdb_type == "data_ptr" || gdb_type == "code_ptr")
+ {
+ reg_info.format = eFormatAddressInfo;
+ reg_info.encoding = eEncodingUint;
+ }
+ else if (gdb_type == "i387_ext" || gdb_type == "float")
+ {
+ reg_info.format = eFormatFloat;
+ reg_info.encoding = eEncodingIEEE754;
+ }
+ }
+
+ // Only update the register set name if we didn't get a "reg_set" attribute.
+ // "set_name" will be empty if we didn't have a "reg_set" attribute.
+ if (!set_name && !gdb_group.empty())
+ set_name.SetCString(gdb_group.c_str());
+
+ reg_info.byte_offset = reg_offset;
+ assert (reg_info.byte_size != 0);
+ reg_offset += reg_info.byte_size;
+ if (!value_regs.empty())
+ {
+ value_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.value_regs = value_regs.data();
+ }
+ if (!invalidate_regs.empty())
+ {
+ invalidate_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.invalidate_regs = invalidate_regs.data();
+ }
+
+ ++prev_reg_num;
+ dyn_reg_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+
+ return true; // Keep iterating through all "reg" elements
+ });
+ return true;
+}
+
+} // namespace {}
+
+
+// query the target of gdb-remote for extended target information
+// return: 'true' on success
+// 'false' on failure
+bool
+ProcessGDBRemote::GetGDBServerRegisterInfo ()
+{
+ // Make sure LLDB has an XML parser it can use first
+ if (!XMLDocument::XMLEnabled())
+ return false;
+
+ // redirect libxml2's error handler since the default prints to stdout
+
+ GDBRemoteCommunicationClient & comm = m_gdb_comm;
+
+ // check that we have extended feature read support
+ if ( !comm.GetQXferFeaturesReadSupported( ) )
+ return false;
+
+ // request the target xml file
+ std::string raw;
+ lldb_private::Error lldberr;
+ if (!comm.ReadExtFeature(ConstString("features"),
+ ConstString("target.xml"),
+ raw,
+ lldberr))
+ {
+ return false;
+ }
+
+
+ XMLDocument xml_document;
+
+ if (xml_document.ParseMemory(raw.c_str(), raw.size(), "target.xml"))
+ {
+ GdbServerTargetInfo target_info;
+
+ XMLNode target_node = xml_document.GetRootElement("target");
+ if (target_node)
+ {
+ XMLNode feature_node;
+ target_node.ForEachChildElement([&target_info, this, &feature_node](const XMLNode &node) -> bool
+ {
+ llvm::StringRef name = node.GetName();
+ if (name == "architecture")
+ {
+ node.GetElementText(target_info.arch);
+ }
+ else if (name == "osabi")
+ {
+ node.GetElementText(target_info.osabi);
+ }
+ else if (name == "xi:include" || name == "include")
+ {
+ llvm::StringRef href = node.GetAttributeValue("href");
+ if (!href.empty())
+ target_info.includes.push_back(href.str());
+ }
+ else if (name == "feature")
+ {
+ feature_node = node;
+ }
+ else if (name == "groups")
+ {
+ node.ForEachChildElementWithName("group", [&target_info](const XMLNode &node) -> bool {
+ uint32_t set_id = UINT32_MAX;
+ RegisterSetInfo set_info;
+
+ node.ForEachAttribute([&set_id, &set_info](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
+ if (name == "id")
+ set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
+ if (name == "name")
+ set_info.name = ConstString(value);
+ return true; // Keep iterating through all attributes
+ });
+
+ if (set_id != UINT32_MAX)
+ target_info.reg_set_map[set_id] = set_info;
+ return true; // Keep iterating through all "group" elements
+ });
+ }
+ return true; // Keep iterating through all children of the target_node
+ });
+
+ if (feature_node)
+ {
+ ParseRegisters(feature_node, target_info, this->m_register_info);
+ }
+
+ for (const auto &include : target_info.includes)
+ {
+ // request register file
+ std::string xml_data;
+ if (!comm.ReadExtFeature(ConstString("features"),
+ ConstString(include),
+ xml_data,
+ lldberr))
+ continue;
+
+ XMLDocument include_xml_document;
+ include_xml_document.ParseMemory(xml_data.data(), xml_data.size(), include.c_str());
+ XMLNode include_feature_node = include_xml_document.GetRootElement("feature");
+ if (include_feature_node)
+ {
+ ParseRegisters(include_feature_node, target_info, this->m_register_info);
+ }
+ }
+ this->m_register_info.Finalize(GetTarget().GetArchitecture());
+ }
+ }
+
+ return m_register_info.GetNumRegisters() > 0;
+}
+
+Error
+ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
+{
+ // Make sure LLDB has an XML parser it can use first
+ if (!XMLDocument::XMLEnabled())
+ return Error (0, ErrorType::eErrorTypeGeneric);
+
+ Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s", __FUNCTION__);
+
+ GDBRemoteCommunicationClient & comm = m_gdb_comm;
+
+ // check that we have extended feature read support
+ if (!comm.GetQXferLibrariesSVR4ReadSupported ())
+ return Error (0, ErrorType::eErrorTypeGeneric);
+
+ list.clear ();
+
+ // request the loaded library list
+ std::string raw;
+ lldb_private::Error lldberr;
+ if (!comm.ReadExtFeature (ConstString ("libraries-svr4"), ConstString (""), raw, lldberr))
+ return Error (0, ErrorType::eErrorTypeGeneric);
+
+ // parse the xml file in memory
+ if (log)
+ log->Printf ("parsing: %s", raw.c_str());
+ XMLDocument doc;
+
+ if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml"))
+ return Error (0, ErrorType::eErrorTypeGeneric);
+
+ XMLNode root_element = doc.GetRootElement("library-list-svr4");
+ if (!root_element)
+ return Error();
+
+ // main link map structure
+ llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm");
+ if (!main_lm.empty())
+ {
+ list.m_link_map = StringConvert::ToUInt64(main_lm.data(), LLDB_INVALID_ADDRESS, 0);
+ }
+
+ root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool {
+
+ GDBLoadedModuleInfoList::LoadedModuleInfo module;
+
+ library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
+
+ if (name == "name")
+ module.set_name (value.str());
+ else if (name == "lm")
+ {
+ // the address of the link_map struct.
+ module.set_link_map(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0));
+ }
+ else if (name == "l_addr")
+ {
+ // the displacement as read from the field 'l_addr' of the link_map struct.
+ module.set_base(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0));
+
+ }
+ else if (name == "l_ld")
+ {
+ // the memory address of the libraries PT_DYAMIC section.
+ module.set_dynamic(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0));
+ }
+
+ return true; // Keep iterating over all properties of "library"
+ });
+
+ if (log)
+ {
+ std::string name;
+ lldb::addr_t lm=0, base=0, ld=0;
+
+ module.get_name (name);
+ module.get_link_map (lm);
+ module.get_base (base);
+ module.get_dynamic (ld);
+
+ log->Printf ("found (link_map:0x08%" PRIx64 ", base:0x08%" PRIx64 ", ld:0x08%" PRIx64 ", name:'%s')", lm, base, ld, name.c_str());
+ }
+
+ list.add (module);
+ return true; // Keep iterating over all "library" elements in the root node
+ });
+
+ if (log)
+ log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size());
+
+ return Error();
+}
+
+lldb::ModuleSP
+ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr)
+{
+ Target &target = m_process->GetTarget();
+ ModuleList &modules = target.GetImages();
+ ModuleSP module_sp;
+
+ bool changed = false;
+
+ ModuleSpec module_spec (file, target.GetArchitecture());
+ if ((module_sp = modules.FindFirstModule (module_spec)))
+ {
+ module_sp->SetLoadAddress (target, base_addr, true, changed);
+ }
+ else if ((module_sp = target.GetSharedModule (module_spec)))
+ {
+ module_sp->SetLoadAddress (target, base_addr, true, changed);
+ }
+
+ return module_sp;
+}
+
+size_t
+ProcessGDBRemote::LoadModules ()
+{
+ using lldb_private::process_gdb_remote::ProcessGDBRemote;
+
+ // request a list of loaded libraries from GDBServer
+ GDBLoadedModuleInfoList module_list;
+ if (GetLoadedModuleList (module_list).Fail())
+ return 0;
+
+ // get a list of all the modules
+ ModuleList new_modules;
+
+ for (GDBLoadedModuleInfoList::LoadedModuleInfo & modInfo : module_list.m_list)
+ {
+ std::string mod_name;
+ lldb::addr_t mod_base;
+
+ bool valid = true;
+ valid &= modInfo.get_name (mod_name);
+ valid &= modInfo.get_base (mod_base);
+ if (!valid)
+ continue;
+
+ // hack (cleaner way to get file name only?) (win/unix compat?)
+ size_t marker = mod_name.rfind ('/');
+ if (marker == std::string::npos)
+ marker = 0;
+ else
+ marker += 1;
+
+ FileSpec file (mod_name.c_str()+marker, true);
+ lldb::ModuleSP module_sp = LoadModuleAtAddress (file, mod_base);
+
+ if (module_sp.get())
+ new_modules.Append (module_sp);
+ }
+
+ if (new_modules.GetSize() > 0)
+ {
+ Target & target = m_target;
+
+ new_modules.ForEach ([&target](const lldb::ModuleSP module_sp) -> bool
+ {
+ lldb_private::ObjectFile * obj = module_sp->GetObjectFile ();
+ if (!obj)
+ return true;
+
+ if (obj->GetType () != ObjectFile::Type::eTypeExecutable)
+ return true;
+
+ lldb::ModuleSP module_copy_sp = module_sp;
+ target.SetExecutableModule (module_copy_sp, false);
+ return false;
+ });
+
+ ModuleList &loaded_modules = m_process->GetTarget().GetImages();
+ loaded_modules.AppendIfNeeded (new_modules);
+ m_process->GetTarget().ModulesDidLoad (new_modules);
+ }
+
+ return new_modules.GetSize();
+}
+
+Error
+ProcessGDBRemote::GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr)
+{
+ is_loaded = false;
+ load_addr = LLDB_INVALID_ADDRESS;
+
+ std::string file_path = file.GetPath(false);
+ if (file_path.empty ())
+ return Error("Empty file name specified");
+
+ StreamString packet;
+ packet.PutCString("qFileLoadAddress:");
+ packet.PutCStringAsRawHex8(file_path.c_str());
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), response, false) != GDBRemoteCommunication::PacketResult::Success)
+ return Error("Sending qFileLoadAddress packet failed");
+
+ if (response.IsErrorResponse())
+ {
+ if (response.GetError() == 1)
+ {
+ // The file is not loaded into the inferior
+ is_loaded = false;
+ load_addr = LLDB_INVALID_ADDRESS;
+ return Error();
+ }
+
+ return Error("Fetching file load address from remote server returned an error");
+ }
+
+ if (response.IsNormalResponse())
+ {
+ is_loaded = true;
+ load_addr = response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ return Error();
+ }
+
+ return Error("Unknown error happened during sending the load address packet");
+}
+
+
+void
+ProcessGDBRemote::ModulesDidLoad (ModuleList &module_list)
+{
+ // We must call the lldb_private::Process::ModulesDidLoad () first before we do anything
+ Process::ModulesDidLoad (module_list);
+
+ // After loading shared libraries, we can ask our remote GDB server if
+ // it needs any symbols.
+ m_gdb_comm.ServeSymbolLookups(this);
+}
+
+
+class CommandObjectProcessGDBRemoteSpeedTest: public CommandObjectParsed
+{
+public:
+ CommandObjectProcessGDBRemoteSpeedTest(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet speed-test",
+ "Tests packet speeds of various sizes to determine the performance characteristics of the GDB remote connection. ",
+ NULL),
+ m_option_group (interpreter),
+ m_num_packets (LLDB_OPT_SET_1, false, "count", 'c', 0, eArgTypeCount, "The number of packets to send of each varying size (default is 1000).", 1000),
+ m_max_send (LLDB_OPT_SET_1, false, "max-send", 's', 0, eArgTypeCount, "The maximum number of bytes to send in a packet. Sizes increase in powers of 2 while the size is less than or equal to this option value. (default 1024).", 1024),
+ m_max_recv (LLDB_OPT_SET_1, false, "max-receive", 'r', 0, eArgTypeCount, "The maximum number of bytes to receive in a packet. Sizes increase in powers of 2 while the size is less than or equal to this option value. (default 1024).", 1024),
+ m_json (LLDB_OPT_SET_1, false, "json", 'j', "Print the output as JSON data for easy parsing.", false, true)
+ {
+ m_option_group.Append (&m_num_packets, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_max_send, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_max_recv, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_json, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectProcessGDBRemoteSpeedTest ()
+ {
+ }
+
+
+ Options *
+ GetOptions () override
+ {
+ return &m_option_group;
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result) override
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ StreamSP output_stream_sp (m_interpreter.GetDebugger().GetAsyncOutputStream());
+ result.SetImmediateOutputStream (output_stream_sp);
+
+ const uint32_t num_packets = (uint32_t)m_num_packets.GetOptionValue().GetCurrentValue();
+ const uint64_t max_send = m_max_send.GetOptionValue().GetCurrentValue();
+ const uint64_t max_recv = m_max_recv.GetOptionValue().GetCurrentValue();
+ const bool json = m_json.GetOptionValue().GetCurrentValue();
+ if (output_stream_sp)
+ process->GetGDBRemote().TestPacketSpeed (num_packets, max_send, max_recv, json, *output_stream_sp);
+ else
+ {
+ process->GetGDBRemote().TestPacketSpeed (num_packets, max_send, max_recv, json, result.GetOutputStream());
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' takes no arguments", m_cmd_name.c_str());
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+protected:
+ OptionGroupOptions m_option_group;
+ OptionGroupUInt64 m_num_packets;
+ OptionGroupUInt64 m_max_send;
+ OptionGroupUInt64 m_max_recv;
+ OptionGroupBoolean m_json;
+
+};
+
class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed
{
private:
@@ -3410,7 +4731,7 @@ public:
}
bool
- DoExecute (Args& command, CommandReturnObject &result)
+ DoExecute (Args& command, CommandReturnObject &result) override
{
const size_t argc = command.GetArgumentCount();
if (argc == 0)
@@ -3450,7 +4771,7 @@ public:
}
bool
- DoExecute (Args& command, CommandReturnObject &result)
+ DoExecute (Args& command, CommandReturnObject &result) override
{
const size_t argc = command.GetArgumentCount();
if (argc == 0)
@@ -3498,7 +4819,7 @@ public:
}
bool
- DoExecute (Args& command, CommandReturnObject &result)
+ DoExecute (Args& command, CommandReturnObject &result) override
{
const size_t argc = command.GetArgumentCount();
if (argc == 0)
@@ -3556,7 +4877,7 @@ public:
}
bool
- DoExecute (const char *command, CommandReturnObject &result)
+ DoExecute (const char *command, CommandReturnObject &result) override
{
if (command == NULL || command[0] == '\0')
{
@@ -3605,6 +4926,7 @@ public:
LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessGDBRemotePacketSend (interpreter)));
LoadSubCommand ("monitor", CommandObjectSP (new CommandObjectProcessGDBRemotePacketMonitor (interpreter)));
LoadSubCommand ("xfer-size", CommandObjectSP (new CommandObjectProcessGDBRemotePacketXferSize (interpreter)));
+ LoadSubCommand ("speed-test", CommandObjectSP (new CommandObjectProcessGDBRemoteSpeedTest (interpreter)));
}
~CommandObjectProcessGDBRemotePacket ()
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index e0c460a202d6..0a5e4a8a41b4 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -34,29 +34,32 @@
#include "Utility/StringExtractor.h"
#include "GDBRemoteRegisterContext.h"
+namespace lldb_private {
+namespace process_gdb_remote {
+
class ThreadGDBRemote;
-class ProcessGDBRemote : public lldb_private::Process
+class ProcessGDBRemote : public Process
{
public:
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
static lldb::ProcessSP
- CreateInstance (lldb_private::Target& target,
- lldb_private::Listener &listener,
- const lldb_private::FileSpec *crash_file_path);
+ CreateInstance (Target& target,
+ Listener &listener,
+ const FileSpec *crash_file_path);
static void
Initialize();
static void
- DebuggerInitialize (lldb_private::Debugger &debugger);
+ DebuggerInitialize (Debugger &debugger);
static void
Terminate();
- static lldb_private::ConstString
+ static ConstString
GetPluginNameStatic();
static const char *
@@ -65,7 +68,7 @@ public:
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
- ProcessGDBRemote(lldb_private::Target& target, lldb_private::Listener &listener);
+ ProcessGDBRemote(Target& target, Listener &listener);
virtual
~ProcessGDBRemote();
@@ -73,149 +76,143 @@ public:
//------------------------------------------------------------------
// Check if a given Process
//------------------------------------------------------------------
- virtual bool
- CanDebug (lldb_private::Target &target,
- bool plugin_specified_by_name) override;
+ bool
+ CanDebug (Target &target, bool plugin_specified_by_name) override;
- virtual lldb_private::CommandObject *
+ CommandObject *
GetPluginCommandObject() override;
//------------------------------------------------------------------
// Creating a new process, or attaching to an existing one
//------------------------------------------------------------------
- virtual lldb_private::Error
- WillLaunch (lldb_private::Module* module) override;
+ Error
+ WillLaunch (Module* module) override;
- virtual lldb_private::Error
- DoLaunch (lldb_private::Module *exe_module,
- lldb_private::ProcessLaunchInfo &launch_info) override;
+ Error
+ DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) override;
- virtual void
+ void
DidLaunch () override;
- virtual lldb_private::Error
+ Error
WillAttachToProcessWithID (lldb::pid_t pid) override;
- virtual lldb_private::Error
+ Error
WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) override;
- virtual lldb_private::Error
- DoConnectRemote (lldb_private::Stream *strm, const char *remote_url) override;
+ Error
+ DoConnectRemote (Stream *strm, const char *remote_url) override;
- lldb_private::Error
+ Error
WillLaunchOrAttach ();
-
- virtual lldb_private::Error
- DoAttachToProcessWithID (lldb::pid_t pid) override;
- virtual lldb_private::Error
- DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override;
+ Error
+ DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info) override;
- virtual lldb_private::Error
+ Error
DoAttachToProcessWithName (const char *process_name,
- const lldb_private::ProcessAttachInfo &attach_info) override;
+ const ProcessAttachInfo &attach_info) override;
- virtual void
- DidAttach (lldb_private::ArchSpec &process_arch) override;
+ void
+ DidAttach (ArchSpec &process_arch) override;
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
- virtual lldb_private::ConstString
+ ConstString
GetPluginName() override;
- virtual uint32_t
+ uint32_t
GetPluginVersion() override;
//------------------------------------------------------------------
// Process Control
//------------------------------------------------------------------
- virtual lldb_private::Error
+ Error
WillResume () override;
- virtual lldb_private::Error
+ Error
DoResume () override;
- virtual lldb_private::Error
+ Error
DoHalt (bool &caused_stop) override;
- virtual lldb_private::Error
+ Error
DoDetach (bool keep_stopped) override;
- virtual bool
+ bool
DetachRequiresHalt() override { return true; }
- virtual lldb_private::Error
+ Error
DoSignal (int signal) override;
- virtual lldb_private::Error
+ Error
DoDestroy () override;
- virtual void
+ void
RefreshStateAfterStop() override;
//------------------------------------------------------------------
// Process Queries
//------------------------------------------------------------------
- virtual bool
+ bool
IsAlive () override;
- virtual lldb::addr_t
+ lldb::addr_t
GetImageInfoAddress() override;
//------------------------------------------------------------------
// Process Memory
//------------------------------------------------------------------
- virtual size_t
- DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
+ size_t
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error) override;
- virtual size_t
- DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error) override;
+ size_t
+ DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, Error &error) override;
- virtual lldb::addr_t
- DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error) override;
+ lldb::addr_t
+ DoAllocateMemory (size_t size, uint32_t permissions, Error &error) override;
- virtual lldb_private::Error
- GetMemoryRegionInfo (lldb::addr_t load_addr,
- lldb_private::MemoryRegionInfo &region_info) override;
+ Error
+ GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &region_info) override;
- virtual lldb_private::Error
+ Error
DoDeallocateMemory (lldb::addr_t ptr) override;
//------------------------------------------------------------------
// Process STDIO
//------------------------------------------------------------------
- virtual size_t
- PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error) override;
+ size_t
+ PutSTDIN (const char *buf, size_t buf_size, Error &error) override;
//----------------------------------------------------------------------
// Process Breakpoints
//----------------------------------------------------------------------
- virtual lldb_private::Error
- EnableBreakpointSite (lldb_private::BreakpointSite *bp_site) override;
+ Error
+ EnableBreakpointSite (BreakpointSite *bp_site) override;
- virtual lldb_private::Error
- DisableBreakpointSite (lldb_private::BreakpointSite *bp_site) override;
+ Error
+ DisableBreakpointSite (BreakpointSite *bp_site) override;
//----------------------------------------------------------------------
// Process Watchpoints
//----------------------------------------------------------------------
- virtual lldb_private::Error
- EnableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true) override;
+ Error
+ EnableWatchpoint (Watchpoint *wp, bool notify = true) override;
- virtual lldb_private::Error
- DisableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true) override;
+ Error
+ DisableWatchpoint (Watchpoint *wp, bool notify = true) override;
- virtual lldb_private::Error
+ Error
GetWatchpointSupportInfo (uint32_t &num) override;
- virtual lldb_private::Error
+ Error
GetWatchpointSupportInfo (uint32_t &num, bool& after) override;
- virtual bool
+ bool
StartNoticingNewThreads() override;
- virtual bool
+ bool
StopNoticingNewThreads() override;
GDBRemoteCommunicationClient &
@@ -224,23 +221,39 @@ public:
return m_gdb_comm;
}
- virtual lldb_private::Error
+ Error
SendEventData(const char *data) override;
//----------------------------------------------------------------------
- // Override SetExitStatus so we can disconnect from the remote GDB server
+ // Override DidExit so we can disconnect from the remote GDB server
//----------------------------------------------------------------------
- virtual bool
- SetExitStatus (int exit_status, const char *cstr) override;
+ void
+ DidExit () override;
void
SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max);
+ bool
+ GetModuleSpec(const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec) override;
+
+ size_t
+ LoadModules() override;
+
+ Error
+ GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) override;
+
+ void
+ ModulesDidLoad (ModuleList &module_list) override;
+
protected:
friend class ThreadGDBRemote;
friend class GDBRemoteCommunicationClient;
friend class GDBRemoteRegisterContext;
+ class GDBLoadedModuleInfoList;
+
//----------------------------------------------------------------------
// Accessors
//----------------------------------------------------------------------
@@ -273,24 +286,24 @@ protected:
void
Clear ( );
- lldb_private::Flags &
+ Flags &
GetFlags ()
{
return m_flags;
}
- const lldb_private::Flags &
+ const Flags &
GetFlags () const
{
return m_flags;
}
- virtual bool
- UpdateThreadList (lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list) override;
+ bool
+ UpdateThreadList (ThreadList &old_thread_list,
+ ThreadList &new_thread_list) override;
- lldb_private::Error
- LaunchAndConnectToDebugserver (const lldb_private::ProcessInfo &process_info);
+ Error
+ LaunchAndConnectToDebugserver (const ProcessInfo &process_info);
void
KillDebugserverProcess ();
@@ -302,20 +315,23 @@ protected:
SetLastStopPacket (const StringExtractorGDBRemote &response);
bool
- ParsePythonTargetDefinition(const lldb_private::FileSpec &target_definition_fspec);
-
- bool
- ParseRegisters(lldb_private::ScriptInterpreterObject *registers_array);
+ ParsePythonTargetDefinition(const FileSpec &target_definition_fspec);
const lldb::DataBufferSP
GetAuxvData() override;
- lldb_private::StructuredData::ObjectSP
+ StructuredData::ObjectSP
GetExtendedInfoForThread (lldb::tid_t tid);
void
GetMaxMemorySize();
+ bool
+ CalculateThreadStopInfo (ThreadGDBRemote *thread);
+
+ size_t
+ UpdateThreadIDsFromStopReplyThreadsValue (std::string &value);
+
//------------------------------------------------------------------
/// Broadcaster event bits definitions.
//------------------------------------------------------------------
@@ -326,19 +342,21 @@ protected:
eBroadcastBitAsyncThreadDidExit = (1 << 2)
};
- lldb_private::Flags m_flags; // Process specific flags (see eFlags enums)
+ Flags m_flags; // Process specific flags (see eFlags enums)
GDBRemoteCommunicationClient m_gdb_comm;
std::atomic<lldb::pid_t> m_debugserver_pid;
- StringExtractorGDBRemote m_last_stop_packet;
- lldb_private::Mutex m_last_stop_packet_mutex;
+ std::vector<StringExtractorGDBRemote> m_stop_packet_stack; // The stop packet stack replaces the last stop packet variable
+ Mutex m_last_stop_packet_mutex;
GDBRemoteDynamicRegisterInfo m_register_info;
- lldb_private::Broadcaster m_async_broadcaster;
- lldb_private::HostThread m_async_thread;
- lldb_private::Mutex m_async_thread_state_mutex;
+ Broadcaster m_async_broadcaster;
+ HostThread m_async_thread;
+ Mutex m_async_thread_state_mutex;
typedef std::vector<lldb::tid_t> tid_collection;
typedef std::vector< std::pair<lldb::tid_t,int> > tid_sig_collection;
typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
+ typedef std::map<uint32_t, std::string> ExpeditedRegisterMap;
tid_collection m_thread_ids; // Thread IDs for all threads. This list gets updated after stopping
+ StructuredData::ObjectSP m_threads_info_sp; // Stop info for all threads if "jThreadsInfo" packet is supported
tid_collection m_continue_c_tids; // 'c' for continue
tid_sig_collection m_continue_C_tids; // 'C' for continue with signal
tid_collection m_continue_s_tids; // 's' for step
@@ -351,6 +369,10 @@ protected:
bool m_destroy_tried_resuming;
lldb::CommandObjectSP m_command_sp;
int64_t m_breakpoint_pc_offset;
+ lldb::tid_t m_initial_tid; // The inital thread ID, given by stub on attach
+
+ bool
+ HandleNotifyPacket(StringExtractorGDBRemote &packet);
bool
StartAsyncThread ();
@@ -371,6 +393,27 @@ protected:
lldb::StateType
SetThreadStopInfo (StringExtractor& stop_packet);
+ lldb::StateType
+ SetThreadStopInfo (StructuredData::Dictionary *thread_dict);
+
+ lldb::ThreadSP
+ SetThreadStopInfo (lldb::tid_t tid,
+ ExpeditedRegisterMap &expedited_register_map,
+ uint8_t signo,
+ const std::string &thread_name,
+ const std::string &reason,
+ const std::string &description,
+ uint32_t exc_type,
+ const std::vector<lldb::addr_t> &exc_data,
+ lldb::addr_t thread_dispatch_qaddr,
+ bool queue_vars_valid,
+ std::string &queue_name,
+ lldb::QueueKind queue_kind,
+ uint64_t queue_serial);
+
+ void
+ HandleStopReplySequence ();
+
void
ClearThreadIDList ();
@@ -378,25 +421,36 @@ protected:
UpdateThreadIDList ();
void
- DidLaunchOrAttach (lldb_private::ArchSpec& process_arch);
+ DidLaunchOrAttach (ArchSpec& process_arch);
- lldb_private::Error
+ Error
ConnectToDebugserver (const char *host_port);
const char *
GetDispatchQueueNameForThread (lldb::addr_t thread_dispatch_qaddr,
std::string &dispatch_queue_name);
- lldb_private::DynamicLoader *
+ DynamicLoader *
GetDynamicLoader () override;
+ // Query remote GDBServer for register information
+ bool
+ GetGDBServerRegisterInfo ();
+
+ // Query remote GDBServer for a detailed loaded library list
+ Error
+ GetLoadedModuleList (GDBLoadedModuleInfoList &);
+
+ lldb::ModuleSP
+ LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr);
+
private:
//------------------------------------------------------------------
// For ProcessGDBRemote only
//------------------------------------------------------------------
static bool
NewThreadNotifyBreakpointHit (void *baton,
- lldb_private::StoppointCallbackContext *context,
+ StoppointCallbackContext *context,
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id);
@@ -404,4 +458,7 @@ private:
};
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
#endif // liblldb_ProcessGDBRemote_h_
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
index 15b861feaa82..d4726adc890e 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
@@ -9,6 +9,8 @@
#include "ProcessGDBRemoteLog.h"
+#include <mutex>
+
#include "lldb/Interpreter/Args.h"
#include "lldb/Core/StreamFile.h"
@@ -16,6 +18,7 @@
using namespace lldb;
using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
// We want to avoid global constructors where code needs to be run so here we
@@ -32,6 +35,22 @@ GetLog ()
return g_log;
}
+void
+ProcessGDBRemoteLog::Initialize()
+{
+ static ConstString g_name("gdb-remote");
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, [](){
+ Log::Callbacks log_callbacks = {
+ DisableLog,
+ EnableLog,
+ ListLogCategories
+ };
+
+ Log::RegisterLogChannel (g_name, log_callbacks);
+ });
+}
Log *
ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (uint32_t mask)
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
index 93734067f133..3cd974d7d821 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
@@ -32,26 +32,35 @@
#define GDBR_LOG_ALL (UINT32_MAX)
#define GDBR_LOG_DEFAULT GDBR_LOG_PACKETS
+namespace lldb_private {
+namespace process_gdb_remote {
+
class ProcessGDBRemoteLog
{
public:
- static lldb_private::Log *
+ static void
+ Initialize();
+
+ static Log *
GetLogIfAllCategoriesSet(uint32_t mask = 0);
- static lldb_private::Log *
+ static Log *
GetLogIfAnyCategoryIsSet (uint32_t mask);
static void
- DisableLog (const char **categories, lldb_private::Stream *feedback_strm);
+ DisableLog (const char **categories, Stream *feedback_strm);
- static lldb_private::Log *
- EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories, lldb_private::Stream *feedback_strm);
+ static Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm);
static void
- ListLogCategories (lldb_private::Stream *strm);
+ ListLogCategories (Stream *strm);
static void
LogIf (uint32_t mask, const char *format, ...);
};
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
#endif // liblldb_ProcessGDBRemoteLog_h_
diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
index 5c70cb5427cb..59c701d75a68 100644
--- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
+++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -21,6 +21,7 @@
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Target.h"
+#include "lldb/Target/UnixSignals.h"
#include "lldb/Target/Unwind.h"
#include "ProcessGDBRemote.h"
@@ -29,6 +30,7 @@
using namespace lldb;
using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
//----------------------------------------------------------------------
// Thread Registers
@@ -38,9 +40,11 @@ ThreadGDBRemote::ThreadGDBRemote (Process &process, lldb::tid_t tid) :
Thread(process, tid),
m_thread_name (),
m_dispatch_queue_name (),
- m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS)
+ m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS),
+ m_queue_kind(eQueueKindUnknown),
+ m_queue_serial(0)
{
- ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)",
+ ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)",
this,
process.GetID(),
GetID());
@@ -64,10 +68,36 @@ ThreadGDBRemote::GetName ()
return m_thread_name.c_str();
}
+void
+ThreadGDBRemote::ClearQueueInfo ()
+{
+ m_dispatch_queue_name.clear();
+ m_queue_kind = eQueueKindUnknown;
+ m_queue_serial = 0;
+}
+
+void
+ThreadGDBRemote::SetQueueInfo (std::string &&queue_name, QueueKind queue_kind, uint64_t queue_serial)
+{
+ m_dispatch_queue_name = queue_name;
+ m_queue_kind = queue_kind;
+ m_queue_serial = queue_serial;
+}
+
const char *
ThreadGDBRemote::GetQueueName ()
{
+ // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...)
+ // with valid information that was gleaned from the stop reply packet. In this case we trust
+ // that the info is valid in m_dispatch_queue_name without refetching it
+ if (CachedQueueInfoIsValid())
+ {
+ if (m_dispatch_queue_name.empty())
+ return nullptr;
+ else
+ return m_dispatch_queue_name.c_str();
+ }
// Always re-fetch the dispatch queue name since it can change
if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
@@ -77,13 +107,12 @@ ThreadGDBRemote::GetQueueName ()
{
SystemRuntime *runtime = process_sp->GetSystemRuntime ();
if (runtime)
- {
m_dispatch_queue_name = runtime->GetQueueNameFromThreadQAddress (m_thread_dispatch_qaddr);
- }
- if (m_dispatch_queue_name.length() > 0)
- {
+ else
+ m_dispatch_queue_name.clear();
+
+ if (!m_dispatch_queue_name.empty())
return m_dispatch_queue_name.c_str();
- }
}
}
return NULL;
@@ -92,6 +121,12 @@ ThreadGDBRemote::GetQueueName ()
queue_id_t
ThreadGDBRemote::GetQueueID ()
{
+ // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...)
+ // with valid information that was gleaned from the stop reply packet. In this case we trust
+ // that the info is valid in m_dispatch_queue_name without refetching it
+ if (CachedQueueInfoIsValid())
+ return m_queue_serial;
+
if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
{
ProcessSP process_sp (GetProcess());
@@ -147,7 +182,7 @@ ThreadGDBRemote::FetchThreadExtendedInfo ()
{
StructuredData::ObjectSP object_sp;
const lldb::user_id_t tid = GetProtocolID();
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD));
+ Log *log(GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD));
if (log)
log->Printf ("Fetching extended information for thread %4.4" PRIx64, tid);
ProcessSP process_sp (GetProcess());
@@ -164,7 +199,7 @@ ThreadGDBRemote::WillResume (StateType resume_state)
{
int signo = GetResumeSignal();
const lldb::user_id_t tid = GetProtocolID();
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD));
+ Log *log(GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD));
if (log)
log->Printf ("Resuming thread: %4.4" PRIx64 " with state: %s.", tid, StateAsCString(resume_state));
@@ -282,12 +317,7 @@ ThreadGDBRemote::CalculateStopInfo ()
{
ProcessSP process_sp (GetProcess());
if (process_sp)
- {
- StringExtractorGDBRemote stop_packet;
- ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
- if (gdb_process->GetGDBRemote().GetThreadStopInfo(GetProtocolID(), stop_packet))
- return gdb_process->SetThreadStopInfo (stop_packet) == eStateStopped;
- }
+ return static_cast<ProcessGDBRemote *>(process_sp.get())->CalculateThreadStopInfo(this);
return false;
}
diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
index a204a917ecb3..175433a3e20c 100644
--- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
+++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
@@ -17,45 +17,49 @@
#include "lldb/Target/Thread.h"
class StringExtractor;
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
class ProcessGDBRemote;
-class ThreadGDBRemote : public lldb_private::Thread
+class ThreadGDBRemote : public Thread
{
public:
- ThreadGDBRemote (lldb_private::Process &process, lldb::tid_t tid);
+ ThreadGDBRemote (Process &process, lldb::tid_t tid);
virtual
~ThreadGDBRemote ();
- virtual void
- WillResume (lldb::StateType resume_state);
+ void
+ WillResume (lldb::StateType resume_state) override;
- virtual void
- RefreshStateAfterStop();
+ void
+ RefreshStateAfterStop() override;
- virtual const char *
- GetName ();
+ const char *
+ GetName () override;
- virtual const char *
- GetQueueName ();
+ const char *
+ GetQueueName () override;
- virtual lldb::queue_id_t
- GetQueueID ();
+ lldb::queue_id_t
+ GetQueueID () override;
- virtual lldb::QueueSP
- GetQueue ();
+ lldb::QueueSP
+ GetQueue () override;
lldb::addr_t
- GetQueueLibdispatchQueueAddress ();
+ GetQueueLibdispatchQueueAddress () override;
- virtual lldb::RegisterContextSP
- GetRegisterContext ();
+ lldb::RegisterContextSP
+ GetRegisterContext () override;
- virtual lldb::RegisterContextSP
- CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame (StackFrame *frame) override;
void
- Dump (lldb_private::Log *log, uint32_t index);
+ Dump (Log *log, uint32_t index);
static bool
ThreadIDIsValid (lldb::tid_t thread);
@@ -67,7 +71,7 @@ public:
GetBasicInfoAsString ();
void
- SetName (const char *name)
+ SetName (const char *name) override
{
if (name && name[0])
m_thread_name.assign (name);
@@ -87,8 +91,14 @@ public:
m_thread_dispatch_qaddr = thread_dispatch_qaddr;
}
- lldb_private::StructuredData::ObjectSP
- FetchThreadExtendedInfo ();
+ void
+ ClearQueueInfo ();
+
+ void
+ SetQueueInfo (std::string &&queue_name, lldb::QueueKind queue_kind, uint64_t queue_serial);
+
+ StructuredData::ObjectSP
+ FetchThreadExtendedInfo () override;
protected:
@@ -97,13 +107,20 @@ protected:
bool
PrivateSetRegisterValue (uint32_t reg,
StringExtractor &response);
-
+
+ bool
+ CachedQueueInfoIsValid() const
+ {
+ return m_queue_kind != lldb::eQueueKindUnknown;
+ }
//------------------------------------------------------------------
// Member variables.
//------------------------------------------------------------------
std::string m_thread_name;
std::string m_dispatch_queue_name;
lldb::addr_t m_thread_dispatch_qaddr;
+ lldb::QueueKind m_queue_kind; // Queue info from stop reply/stop info for thread
+ uint64_t m_queue_serial; // Queue info from stop reply/stop info for thread
//------------------------------------------------------------------
// Member variables.
//------------------------------------------------------------------
@@ -111,10 +128,11 @@ protected:
void
SetStopInfoFromPacket (StringExtractor &stop_packet, uint32_t stop_id);
- virtual bool
- CalculateStopInfo ();
-
-
+ bool
+ CalculateStopInfo () override;
};
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
#endif // liblldb_ThreadGDBRemote_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
index 8935f7143e48..75934f966bcd 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -51,6 +51,7 @@ DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF* dwarf2Data) :
m_producer_version_major (0),
m_producer_version_minor (0),
m_producer_version_update (0),
+ m_language_type (eLanguageTypeUnknown),
m_is_dwarf64 (false)
{
}
@@ -68,6 +69,7 @@ DWARFCompileUnit::Clear()
m_func_aranges_ap.reset();
m_user_data = NULL;
m_producer = eProducerInvalid;
+ m_language_type = eLanguageTypeUnknown;
m_is_dwarf64 = false;
}
@@ -444,6 +446,31 @@ DWARFCompileUnit::BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data,
}
}
+ if (debug_aranges->IsEmpty())
+ {
+ // We got nothing from the functions, maybe we have a line tables only
+ // situation. Check the line tables and build the arange table from this.
+ SymbolContext sc;
+ sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this);
+ if (sc.comp_unit)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+
+ if (line_table)
+ {
+ LineTable::FileAddressRanges file_ranges;
+ const bool append = true;
+ const size_t num_ranges = line_table->GetContiguousFileAddressRanges (file_ranges, append);
+ 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());
+ printf ("0x%8.8x: [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", GetOffset(), range.GetRangeBase(), range.GetRangeEnd());
+ }
+ }
+ }
+ }
+
// Keep memory down by clearing DIEs if this generate function
// caused them to be parsed
if (clear_dies)
@@ -1042,6 +1069,35 @@ DWARFCompileUnit::GetProducerVersionUpdate()
return m_producer_version_update;
}
+LanguageType
+DWARFCompileUnit::LanguageTypeFromDWARF(uint64_t val)
+{
+ // Note: user languages between lo_user and hi_user
+ // must be handled explicitly here.
+ switch (val)
+ {
+ case DW_LANG_Mips_Assembler:
+ return eLanguageTypeMipsAssembler;
+ case 0x8e57: // FIXME: needs to be added to llvm
+ return eLanguageTypeExtRenderScript;
+ default:
+ return static_cast<LanguageType>(val);
+ }
+}
+
+LanguageType
+DWARFCompileUnit::GetLanguageType()
+{
+ if (m_language_type != eLanguageTypeUnknown)
+ return m_language_type;
+
+ const DWARFDebugInfoEntry *die = GetCompileUnitDIEOnly();
+ if (die)
+ m_language_type = LanguageTypeFromDWARF(
+ die->GetAttributeValueAsUnsigned(m_dwarf2Data, this, DW_AT_language, 0));
+ return m_language_type;
+}
+
bool
DWARFCompileUnit::IsDWARF64() const
{
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
index 3e904892dbd5..93c8df822dcc 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
@@ -10,6 +10,7 @@
#ifndef SymbolFileDWARF_DWARFCompileUnit_h_
#define SymbolFileDWARF_DWARFCompileUnit_h_
+#include "lldb/lldb-enumerations.h"
#include "DWARFDebugInfoEntry.h"
#include "SymbolFileDWARF.h"
@@ -186,6 +187,12 @@ public:
uint32_t
GetProducerVersionUpdate();
+ static lldb::LanguageType
+ LanguageTypeFromDWARF(uint64_t val);
+
+ lldb::LanguageType
+ GetLanguageType();
+
bool
IsDWARF64() const;
@@ -204,6 +211,7 @@ protected:
uint32_t m_producer_version_major;
uint32_t m_producer_version_minor;
uint32_t m_producer_version_update;
+ lldb::LanguageType m_language_type;
bool m_is_dwarf64;
void
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
index 6a8c4e6d57b9..0ad1f1a3a95a 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -1582,17 +1582,21 @@ DWARFDebugInfoEntry::GetName
DWARFFormValue form_value;
if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
return form_value.AsCString(&dwarf2Data->get_debug_str_data());
- else
+ else if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value))
{
- if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value))
- {
- DWARFCompileUnitSP cu_sp_ptr;
- const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(), &cu_sp_ptr);
- if (die)
- return die->GetName(dwarf2Data, cu_sp_ptr.get());
- }
+ DWARFCompileUnitSP cu_sp_ptr;
+ const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(), &cu_sp_ptr);
+ if (die)
+ return die->GetName(dwarf2Data, cu_sp_ptr.get());
}
- return NULL;
+ else if (GetAttributeValue(dwarf2Data, cu, DW_AT_abstract_origin, form_value))
+ {
+ DWARFCompileUnitSP cu_sp_ptr;
+ const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(), &cu_sp_ptr);
+ if (die)
+ return die->GetName(dwarf2Data, cu_sp_ptr.get());
+ }
+ return nullptr;
}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
index 11589aede708..48e11bd80089 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
@@ -488,7 +488,6 @@ DWARFDebugLine::ParseSupportFiles (const lldb::ModuleSP &module_sp,
lldb::offset_t offset = stmt_list;
// Skip the total length
(void)debug_line_data.GetDWARFInitialLength(&offset);
- const char * s;
uint32_t version = debug_line_data.GetU16(&offset);
if (version < 2 || version > 4)
return false;
@@ -502,68 +501,38 @@ DWARFDebugLine::ParseSupportFiles (const lldb::ModuleSP &module_sp,
// Skip opcode base, and all opcode lengths
const uint8_t opcode_base = debug_line_data.GetU8(&offset);
offset += opcode_base - 1;
- std::vector<std::string> include_directories;
- include_directories.push_back(""); // Directory at index zero doesn't exist
+ std::vector<FileSpec> include_directories{{}}; // Directory at index zero doesn't exist
while (offset < end_prologue_offset)
{
- s = debug_line_data.GetCStr(&offset);
- if (s && s[0])
- include_directories.push_back(s);
+ FileSpec dir{debug_line_data.GetCStr(&offset), false};
+ if (dir)
+ include_directories.emplace_back(std::move(dir));
else
break;
}
- std::string fullpath;
- std::string remapped_fullpath;
while (offset < end_prologue_offset)
{
- const char* path = debug_line_data.GetCStr( &offset );
- if (path && path[0])
+ FileSpec file_spec{debug_line_data.GetCStr(&offset), false};
+ if (file_spec)
{
- uint32_t dir_idx = debug_line_data.GetULEB128( &offset );
+ uint32_t dir_idx = debug_line_data.GetULEB128(&offset);
debug_line_data.Skip_LEB128(&offset); // Skip mod_time
debug_line_data.Skip_LEB128(&offset); // Skip length
- if (path[0] == '/')
- {
- // The path starts with a directory delimiter, so we are done.
- if (module_sp->RemapSourceFile (path, fullpath))
- support_files.Append(FileSpec (fullpath.c_str(), false));
- else
- support_files.Append(FileSpec (path, false));
- }
- else
+ if (file_spec.IsRelative())
{
- if (dir_idx > 0 && dir_idx < include_directories.size())
- {
- if (cu_comp_dir && include_directories[dir_idx][0] != '/')
- {
- fullpath = cu_comp_dir;
-
- if (*fullpath.rbegin() != '/')
- fullpath += '/';
- fullpath += include_directories[dir_idx];
-
- }
- else
- fullpath = include_directories[dir_idx];
- }
- else if (cu_comp_dir && cu_comp_dir[0])
+ if (0 < dir_idx && dir_idx < include_directories.size())
{
- fullpath = cu_comp_dir;
+ const FileSpec &dir = include_directories[dir_idx];
+ file_spec.PrependPathComponent(dir);
}
-
- if (!fullpath.empty())
- {
- if (*fullpath.rbegin() != '/')
- fullpath += '/';
- }
- fullpath += path;
- if (module_sp->RemapSourceFile (fullpath.c_str(), remapped_fullpath))
- support_files.Append(FileSpec (remapped_fullpath.c_str(), false));
- else
- support_files.Append(FileSpec (fullpath.c_str(), false));
+ if (file_spec.IsRelative())
+ file_spec.PrependPathComponent(cu_comp_dir);
}
-
+ std::string remapped_file;
+ if (module_sp->RemapSourceFile(file_spec.GetCString(), remapped_file))
+ file_spec.SetFile(remapped_file, false);
+ support_files.Append(file_spec);
}
}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
index 2be5d90c37b2..3a99d2b33878 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
@@ -100,6 +100,14 @@ public:
const char *
GetQualifiedName () const;
+ // Same as GetQaulifiedName, but the life time of the returned string will
+ // be that of the LLDB session.
+ lldb_private::ConstString
+ GetQualifiedNameAsConstString () const
+ {
+ return lldb_private::ConstString (GetQualifiedName ());
+ }
+
protected:
typedef std::vector<Entry> collection;
collection m_entries;
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
index a8c550e9176f..c733832e4f4d 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -191,7 +191,7 @@ DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* off
// Set the string value to also be the data for inlined cstr form values only
// 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;
+ m_value.data = (const uint8_t*)m_value.value.cstr; break;
case DW_FORM_exprloc:
case DW_FORM_block: m_value.value.uval = data.GetULEB128(offset_ptr); is_block = true; break;
case DW_FORM_block1: m_value.value.uval = data.GetU8(offset_ptr); is_block = true; break;
diff --git a/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
index e4626900d816..c49237b8fbbc 100644
--- a/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
+++ b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
@@ -69,7 +69,7 @@ NameToDIE::Dump (Stream *s)
for (uint32_t i=0; i<size; ++i)
{
const char *cstr = m_map.GetCStringAtIndex(i);
- s->Printf("%p: {0x%8.8x} \"%s\"\n", cstr, m_map.GetValueAtIndexUnchecked(i), cstr);
+ s->Printf("%p: {0x%8.8x} \"%s\"\n", (const void *)cstr, m_map.GetValueAtIndexUnchecked(i), cstr);
}
}
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 7ba4f52ac297..dafd389449a2 100644
--- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -26,7 +26,10 @@
#include "llvm/Support/Casting.h"
+#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/Scalar.h"
@@ -36,6 +39,8 @@
#include "lldb/Core/Timer.h"
#include "lldb/Core/Value.h"
+#include "lldb/Expression/ClangModulesDeclVendor.h"
+
#include "lldb/Host/Host.h"
#include "lldb/Symbol/Block.h"
@@ -515,6 +520,7 @@ SymbolFileDWARF::SymbolFileDWARF(ObjectFile* objfile) :
m_indexed (false),
m_is_external_ast_source (false),
m_using_apple_tables (false),
+ m_fetched_external_modules (false),
m_supports_DW_AT_APPLE_objc_complete_type (eLazyBoolCalculate),
m_ranges(),
m_unique_ast_type_map ()
@@ -966,39 +972,25 @@ SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx)
const DWARFDebugInfoEntry * cu_die = dwarf_cu->GetCompileUnitDIEOnly ();
if (cu_die)
{
- const char * cu_die_name = cu_die->GetName(this, dwarf_cu);
- const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, NULL);
- LanguageType cu_language = (LanguageType)cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0);
- if (cu_die_name)
+ FileSpec cu_file_spec{cu_die->GetName(this, dwarf_cu), false};
+ if (cu_file_spec)
{
- std::string ramapped_file;
- FileSpec cu_file_spec;
-
- if (cu_die_name[0] == '/' || cu_comp_dir == NULL || cu_comp_dir[0] == '\0')
- {
- // If we have a full path to the compile unit, we don't need to resolve
- // the file. This can be expensive e.g. when the source files are NFS mounted.
- if (module_sp->RemapSourceFile(cu_die_name, ramapped_file))
- cu_file_spec.SetFile (ramapped_file.c_str(), false);
- else
- cu_file_spec.SetFile (cu_die_name, false);
- }
- else
+ // If we have a full path to the compile unit, we don't need to resolve
+ // the file. This can be expensive e.g. when the source files are NFS mounted.
+ if (cu_file_spec.IsRelative())
{
// 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;
- if (module_sp->RemapSourceFile (fullpath.c_str(), ramapped_file))
- cu_file_spec.SetFile (ramapped_file.c_str(), false);
- else
- cu_file_spec.SetFile (fullpath.c_str(), false);
+ const char *cu_comp_dir{cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, nullptr)};
+ cu_file_spec.PrependPathComponent(removeHostnameFromPathname(cu_comp_dir));
}
+ std::string remapped_file;
+ if (module_sp->RemapSourceFile(cu_file_spec.GetCString(), remapped_file))
+ cu_file_spec.SetFile(remapped_file, false);
+
+ LanguageType cu_language = DWARFCompileUnit::LanguageTypeFromDWARF(cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0));
+
cu_sp.reset(new CompileUnit (module_sp,
dwarf_cu,
cu_file_spec,
@@ -1095,7 +1087,54 @@ SymbolFileDWARF::ParseCompileUnitFunction (const SymbolContext& sc, DWARFCompile
Mangled func_name;
if (mangled)
func_name.SetValue(ConstString(mangled), true);
- else if (name)
+ else if (die->GetParent()->Tag() == DW_TAG_compile_unit &&
+ LanguageRuntime::LanguageIsCPlusPlus(dwarf_cu->GetLanguageType()) &&
+ name && strcmp(name, "main") != 0)
+ {
+ // If the mangled name is not present in the DWARF, generate the demangled name
+ // using the decl context. We skip if the function is "main" as its name is
+ // never mangled.
+ bool is_static = false;
+ bool is_variadic = false;
+ unsigned type_quals = 0;
+ std::vector<ClangASTType> param_types;
+ std::vector<clang::ParmVarDecl*> param_decls;
+ const DWARFDebugInfoEntry *decl_ctx_die = NULL;
+ DWARFDeclContext decl_ctx;
+ StreamString sstr;
+
+ die->GetDWARFDeclContext(this, dwarf_cu, decl_ctx);
+ sstr << decl_ctx.GetQualifiedName();
+
+ clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE(dwarf_cu,
+ die,
+ &decl_ctx_die);
+ ParseChildParameters(sc,
+ containing_decl_ctx,
+ dwarf_cu,
+ die,
+ true,
+ is_static,
+ is_variadic,
+ param_types,
+ param_decls,
+ type_quals);
+ sstr << "(";
+ for (size_t i = 0; i < param_types.size(); i++)
+ {
+ if (i > 0)
+ sstr << ", ";
+ sstr << param_types[i].GetTypeName();
+ }
+ if (is_variadic)
+ sstr << ", ...";
+ sstr << ")";
+ if (type_quals & clang::Qualifiers::Const)
+ sstr << " const";
+
+ func_name.SetValue(ConstString(sstr.GetData()), false);
+ }
+ else
func_name.SetValue(ConstString(name), false);
FunctionSP func_sp;
@@ -1153,11 +1192,7 @@ SymbolFileDWARF::ParseCompileUnitLanguage (const SymbolContext& sc)
{
const DWARFDebugInfoEntry *die = dwarf_cu->GetCompileUnitDIEOnly();
if (die)
- {
- const uint32_t language = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0);
- if (language)
- return (lldb::LanguageType)language;
- }
+ return DWARFCompileUnit::LanguageTypeFromDWARF(die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0));
}
return eLanguageTypeUnknown;
}
@@ -1216,6 +1251,25 @@ SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpec
return false;
}
+bool
+SymbolFileDWARF::ParseImportedModules (const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules)
+{
+ assert (sc.comp_unit);
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ if (ClangModulesDeclVendor::LanguageSupportsClangModules(sc.comp_unit->GetLanguage()))
+ {
+ UpdateExternalModuleListIfNeeded();
+ for (const std::pair<uint64_t, const ClangModuleInfo> &external_type_module : m_external_type_modules)
+ {
+ imported_modules.push_back(external_type_module.second.m_name);
+ }
+ }
+ }
+ return false;
+}
+
struct ParseDWARFLineTableCallbackInfo
{
LineTable* line_table;
@@ -2073,8 +2127,9 @@ SymbolFileDWARF::ParseChildMembers
GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, word_width),
accessibility,
anon_field_info.bit_size);
-
- layout_info.field_offsets.insert(std::make_pair(unnamed_bitfield_decl, anon_field_info.bit_offset));
+
+ layout_info.field_offsets.insert(
+ std::make_pair(unnamed_bitfield_decl, anon_field_info.bit_offset));
}
}
last_field_info = this_field_info;
@@ -2124,9 +2179,8 @@ SymbolFileDWARF::ParseChildMembers
bit_size);
GetClangASTContext().SetMetadataAsUserID (field_decl, MakeUserID(die->GetOffset()));
-
- layout_info.field_offsets.insert(std::make_pair(field_decl, field_bit_offset));
+ layout_info.field_offsets.insert(std::make_pair(field_decl, field_bit_offset));
}
else
{
@@ -2261,8 +2315,15 @@ SymbolFileDWARF::ParseChildMembers
}
Type *base_class_type = ResolveTypeUID(encoding_uid);
- assert(base_class_type);
-
+ if (base_class_type == NULL)
+ {
+ GetObjectFile()->GetModule()->ReportError("0x%8.8x: DW_TAG_inheritance failed to resolve the base class at 0x%8.8" PRIx64 " from enclosing type 0x%8.8x. \nPlease file a bug and attach the file at the start of this error message",
+ die->GetOffset(),
+ encoding_uid,
+ parent_die->GetOffset());
+ break;
+ }
+
ClangASTType base_class_clang_type = base_class_type->GetClangFullType();
assert (base_class_clang_type);
if (class_language == eLanguageTypeObjC)
@@ -2287,8 +2348,9 @@ SymbolFileDWARF::ParseChildMembers
}
else
{
- layout_info.base_offsets.insert(std::make_pair(base_class_clang_type.GetAsCXXRecordDecl(),
- clang::CharUnits::fromQuantity(member_byte_offset)));
+ layout_info.base_offsets.insert(
+ std::make_pair(base_class_clang_type.GetAsCXXRecordDecl(),
+ clang::CharUnits::fromQuantity(member_byte_offset)));
}
}
}
@@ -2671,41 +2733,44 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
uint32_t idx;
{
- llvm::DenseMap <const clang::FieldDecl *, uint64_t>::const_iterator pos, end = layout_info.field_offsets.end();
- for (idx = 0, pos = layout_info.field_offsets.begin(); pos != end; ++pos, ++idx)
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t>::const_iterator pos,
+ end = layout_info.field_offsets.end();
+ for (idx = 0, pos = layout_info.field_offsets.begin(); pos != end; ++pos, ++idx)
{
- GetObjectFile()->GetModule()->LogMessage (log,
- "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) field[%u] = { bit_offset=%u, name='%s' }",
- static_cast<void*>(clang_type.GetOpaqueQualType()),
- idx,
- static_cast<uint32_t>(pos->second),
- pos->first->getNameAsString().c_str());
+ GetObjectFile()->GetModule()->LogMessage(
+ log, "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) field[%u] = "
+ "{ bit_offset=%u, name='%s' }",
+ static_cast<void *>(clang_type.GetOpaqueQualType()), idx,
+ 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)
- {
- GetObjectFile()->GetModule()->LogMessage (log,
- "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) base[%u] = { byte_offset=%u, name='%s' }",
- clang_type.GetOpaqueQualType(),
- idx,
- (uint32_t)base_pos->second.getQuantity(),
- base_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)
+ {
+ GetObjectFile()->GetModule()->LogMessage(
+ log, "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) base[%u] "
+ "= { byte_offset=%u, name='%s' }",
+ clang_type.GetOpaqueQualType(), idx, (uint32_t)base_pos->second.getQuantity(),
+ base_pos->first->getNameAsString().c_str());
+ }
}
{
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator vbase_pos, vbase_end = layout_info.vbase_offsets.end();
- for (idx = 0, vbase_pos = layout_info.vbase_offsets.begin(); vbase_pos != vbase_end; ++vbase_pos, ++idx)
- {
- GetObjectFile()->GetModule()->LogMessage (log,
- "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) vbase[%u] = { byte_offset=%u, name='%s' }",
- static_cast<void*>(clang_type.GetOpaqueQualType()),
- idx,
- static_cast<uint32_t>(vbase_pos->second.getQuantity()),
- vbase_pos->first->getNameAsString().c_str());
- }
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator vbase_pos,
+ vbase_end = layout_info.vbase_offsets.end();
+ for (idx = 0, vbase_pos = layout_info.vbase_offsets.begin(); vbase_pos != vbase_end;
+ ++vbase_pos, ++idx)
+ {
+ GetObjectFile()->GetModule()->LogMessage(
+ log, "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) "
+ "vbase[%u] = { byte_offset=%u, name='%s' }",
+ static_cast<void *>(clang_type.GetOpaqueQualType()), idx,
+ static_cast<uint32_t>(vbase_pos->second.getQuantity()),
+ vbase_pos->first->getNameAsString().c_str());
+ }
}
}
m_record_decl_to_layout_map.insert(std::make_pair(record_decl, layout_info));
@@ -2794,7 +2859,60 @@ SymbolFileDWARF::GetFunction (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEn
return false;
}
-
+void
+SymbolFileDWARF::UpdateExternalModuleListIfNeeded()
+{
+ if (m_fetched_external_modules)
+ return;
+ m_fetched_external_modules = true;
+
+ DWARFDebugInfo * debug_info = DebugInfo();
+ debug_info->GetNumCompileUnits();
+
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+
+ const DWARFDebugInfoEntry *die = dwarf_cu->GetCompileUnitDIEOnly();
+ if (die && die->HasChildren() == false)
+ {
+ const uint64_t name_strp = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_name, UINT64_MAX);
+ const uint64_t dwo_path_strp = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_GNU_dwo_name, UINT64_MAX);
+
+ if (name_strp != UINT64_MAX)
+ {
+ if (m_external_type_modules.find(dwo_path_strp) == m_external_type_modules.end())
+ {
+ const char *name = get_debug_str_data().PeekCStr(name_strp);
+ const char *dwo_path = get_debug_str_data().PeekCStr(dwo_path_strp);
+ if (name || dwo_path)
+ {
+ ModuleSP module_sp;
+ if (dwo_path)
+ {
+ ModuleSpec dwo_module_spec;
+ dwo_module_spec.GetFileSpec().SetFile(dwo_path, false);
+ dwo_module_spec.GetArchitecture() = m_obj_file->GetModule()->GetArchitecture();
+ //printf ("Loading dwo = '%s'\n", dwo_path);
+ Error error = ModuleList::GetSharedModule (dwo_module_spec, module_sp, NULL, NULL, NULL);
+ }
+
+ if (dwo_path_strp != LLDB_INVALID_UID)
+ {
+ m_external_type_modules[dwo_path_strp] = ClangModuleInfo { ConstString(name), module_sp };
+ }
+ else
+ {
+ // This hack should be removed promptly once clang emits both.
+ m_external_type_modules[name_strp] = ClangModuleInfo { ConstString(name), module_sp };
+ }
+ }
+ }
+ }
+ }
+ }
+}
SymbolFileDWARF::GlobalVariableMap &
SymbolFileDWARF::GetGlobalAranges()
@@ -3455,16 +3573,18 @@ SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append
bool
SymbolFileDWARF::ResolveFunction (dw_offset_t die_offset,
DWARFCompileUnit *&dwarf_cu,
+ bool include_inlines,
SymbolContextList& sc_list)
{
const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
- return ResolveFunction (dwarf_cu, die, sc_list);
+ return ResolveFunction (dwarf_cu, die, include_inlines, sc_list);
}
bool
SymbolFileDWARF::ResolveFunction (DWARFCompileUnit *cu,
const DWARFDebugInfoEntry *die,
+ bool include_inlines,
SymbolContextList& sc_list)
{
SymbolContext sc;
@@ -3473,7 +3593,7 @@ SymbolFileDWARF::ResolveFunction (DWARFCompileUnit *cu,
return false;
// If we were passed a die that is not a function, just return false...
- if (die->Tag() != DW_TAG_subprogram && die->Tag() != DW_TAG_inlined_subroutine)
+ if (! (die->Tag() == DW_TAG_subprogram || (include_inlines && die->Tag() == DW_TAG_inlined_subroutine)))
return false;
const DWARFDebugInfoEntry* inlined_die = NULL;
@@ -3520,12 +3640,13 @@ SymbolFileDWARF::ResolveFunction (DWARFCompileUnit *cu,
void
SymbolFileDWARF::FindFunctions (const ConstString &name,
const NameToDIE &name_to_die,
+ bool include_inlines,
SymbolContextList& sc_list)
{
DIEArray die_offsets;
if (name_to_die.Find (name, die_offsets))
{
- ParseFunctions (die_offsets, sc_list);
+ ParseFunctions (die_offsets, include_inlines, sc_list);
}
}
@@ -3533,12 +3654,13 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
void
SymbolFileDWARF::FindFunctions (const RegularExpression &regex,
const NameToDIE &name_to_die,
+ bool include_inlines,
SymbolContextList& sc_list)
{
DIEArray die_offsets;
if (name_to_die.Find (regex, die_offsets))
{
- ParseFunctions (die_offsets, sc_list);
+ ParseFunctions (die_offsets, include_inlines, sc_list);
}
}
@@ -3546,6 +3668,7 @@ SymbolFileDWARF::FindFunctions (const RegularExpression &regex,
void
SymbolFileDWARF::FindFunctions (const RegularExpression &regex,
const DWARFMappedHash::MemoryTable &memory_table,
+ bool include_inlines,
SymbolContextList& sc_list)
{
DIEArray die_offsets;
@@ -3553,24 +3676,23 @@ SymbolFileDWARF::FindFunctions (const RegularExpression &regex,
if (memory_table.AppendAllDIEsThatMatchingRegex (regex, hash_data_array))
{
DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets);
- ParseFunctions (die_offsets, sc_list);
+ ParseFunctions (die_offsets, include_inlines, sc_list);
}
}
void
SymbolFileDWARF::ParseFunctions (const DIEArray &die_offsets,
+ bool include_inlines,
SymbolContextList& sc_list)
{
const size_t num_matches = die_offsets.size();
if (num_matches)
{
- SymbolContext sc;
-
DWARFCompileUnit* dwarf_cu = NULL;
for (size_t i=0; i<num_matches; ++i)
{
const dw_offset_t die_offset = die_offsets[i];
- ResolveFunction (die_offset, dwarf_cu, sc_list);
+ ResolveFunction (die_offset, dwarf_cu, include_inlines, sc_list);
}
}
}
@@ -3761,12 +3883,9 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
continue;
- if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
- continue;
-
if (resolved_dies.find(die) == resolved_dies.end())
{
- if (ResolveFunction (dwarf_cu, die, sc_list))
+ if (ResolveFunction (dwarf_cu, die, include_inlines, sc_list))
resolved_dies.insert(die);
}
}
@@ -3796,12 +3915,9 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
const char *die_name = die->GetName(this, dwarf_cu);
if (ObjCLanguageRuntime::IsPossibleObjCMethodName(die_name))
{
- if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
- continue;
-
if (resolved_dies.find(die) == resolved_dies.end())
{
- if (ResolveFunction (dwarf_cu, die, sc_list))
+ if (ResolveFunction (dwarf_cu, die, include_inlines, sc_list))
resolved_dies.insert(die);
}
}
@@ -3830,15 +3946,12 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
if (die)
{
- if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
- continue;
-
if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
continue;
// If we get to here, the die is good, and we should add it:
if (resolved_dies.find(die) == resolved_dies.end())
- if (ResolveFunction (dwarf_cu, die, sc_list))
+ if (ResolveFunction (dwarf_cu, die, include_inlines, sc_list))
{
bool keep_die = true;
if ((name_type_mask & (eFunctionNameTypeBase|eFunctionNameTypeMethod)) != (eFunctionNameTypeBase|eFunctionNameTypeMethod))
@@ -3907,21 +4020,27 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
if (name_type_mask & eFunctionNameTypeFull)
{
- FindFunctions (name, m_function_fullname_index, sc_list);
+ FindFunctions (name, m_function_fullname_index, include_inlines, sc_list);
// FIXME Temporary workaround for global/anonymous namespace
- // functions on FreeBSD and Linux
-#if defined (__FreeBSD__) || defined (__linux__)
+ // functions debugging FreeBSD and Linux binaries.
// If we didn't find any functions in the global namespace try
// looking in the basename index but ignore any returned
- // functions that have a namespace (ie. mangled names starting with
- // '_ZN') but keep functions which have an anonymous namespace
+ // functions that have a namespace but keep functions which
+ // have an anonymous namespace
+ // TODO: The arch in the object file isn't correct for MSVC
+ // binaries on windows, we should find a way to make it
+ // correct and handle those symbols as well.
if (sc_list.GetSize() == 0)
{
- SymbolContextList temp_sc_list;
- FindFunctions (name, m_function_basename_index, temp_sc_list);
- if (!namespace_decl)
+ ArchSpec arch;
+ if (!namespace_decl &&
+ GetObjectFile()->GetArchitecture(arch) &&
+ (arch.GetTriple().isOSFreeBSD() || arch.GetTriple().isOSLinux() ||
+ arch.GetMachine() == llvm::Triple::hexagon))
{
+ SymbolContextList temp_sc_list;
+ FindFunctions (name, m_function_basename_index, include_inlines, temp_sc_list);
SymbolContext sc;
for (uint32_t i = 0; i < temp_sc_list.GetSize(); i++)
{
@@ -3929,6 +4048,8 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
{
ConstString mangled_name = sc.GetFunctionName(Mangled::ePreferMangled);
ConstString demangled_name = sc.GetFunctionName(Mangled::ePreferDemangled);
+ // Mangled names on Linux and FreeBSD are of the form:
+ // _ZN18function_namespace13function_nameEv.
if (strncmp(mangled_name.GetCString(), "_ZN", 3) ||
!strncmp(demangled_name.GetCString(), "(anonymous namespace)", 21))
{
@@ -3938,7 +4059,6 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
}
}
}
-#endif
}
DIEArray die_offsets;
DWARFCompileUnit *dwarf_cu = NULL;
@@ -3951,16 +4071,13 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu);
if (die)
{
- if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
- continue;
-
if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
continue;
// If we get to here, the die is good, and we should add it:
if (resolved_dies.find(die) == resolved_dies.end())
{
- if (ResolveFunction (dwarf_cu, die, sc_list))
+ if (ResolveFunction (dwarf_cu, die, include_inlines, sc_list))
resolved_dies.insert(die);
}
}
@@ -3980,13 +4097,10 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu);
if (die)
{
- if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
- continue;
-
// If we get to here, the die is good, and we should add it:
if (resolved_dies.find(die) == resolved_dies.end())
{
- if (ResolveFunction (dwarf_cu, die, sc_list))
+ if (ResolveFunction (dwarf_cu, die, include_inlines, sc_list))
resolved_dies.insert(die);
}
}
@@ -3997,7 +4111,7 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
if ((name_type_mask & eFunctionNameTypeSelector) && (!namespace_decl || !*namespace_decl))
{
- FindFunctions (name, m_function_selector_index, sc_list);
+ FindFunctions (name, m_function_selector_index, include_inlines, sc_list);
}
}
@@ -4008,9 +4122,10 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
if (log && num_matches > 0)
{
GetObjectFile()->GetModule()->LogMessage (log,
- "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, append=%u, sc_list) => %u",
+ "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, include_inlines=%d, append=%u, sc_list) => %u",
name.GetCString(),
name_type_mask,
+ include_inlines,
append,
num_matches);
}
@@ -4046,7 +4161,7 @@ SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool include_inli
if (m_using_apple_tables)
{
if (m_apple_names_ap.get())
- FindFunctions (regex, *m_apple_names_ap, sc_list);
+ FindFunctions (regex, *m_apple_names_ap, include_inlines, sc_list);
}
else
{
@@ -4054,9 +4169,9 @@ SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool include_inli
if (!m_indexed)
Index ();
- FindFunctions (regex, m_function_basename_index, sc_list);
+ FindFunctions (regex, m_function_basename_index, include_inlines, sc_list);
- FindFunctions (regex, m_function_fullname_index, sc_list);
+ FindFunctions (regex, m_function_fullname_index, include_inlines, sc_list);
}
// Return the number of variable that were appended to the list
@@ -4309,7 +4424,6 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc,
bool skip_artificial,
bool &is_static,
bool &is_variadic,
- TypeList* type_list,
std::vector<ClangASTType>& function_param_types,
std::vector<clang::ParmVarDecl*>& function_param_decls,
unsigned &type_quals) // ,
@@ -6535,7 +6649,6 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
skip_artificial,
is_static,
is_variadic,
- type_list,
function_param_types,
function_param_decls,
type_quals);
@@ -7412,6 +7525,24 @@ SymbolFileDWARF::ParseVariableDIE
dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
SymbolContextScope * symbol_context_scope = NULL;
+ if (!mangled)
+ {
+ // LLDB relies on the mangled name (DW_TAG_linkage_name or DW_AT_MIPS_linkage_name) to
+ // generate fully qualified names of global variables with commands like "frame var j".
+ // For example, if j were an int variable holding a value 4 and declared in a namespace
+ // B which in turn is contained in a namespace A, the command "frame var j" returns
+ // "(int) A::B::j = 4". If the compiler does not emit a linkage name, we should be able
+ // to generate a fully qualified name from the declaration context.
+ if (die->GetParent()->Tag() == DW_TAG_compile_unit &&
+ LanguageRuntime::LanguageIsCPlusPlus(dwarf_cu->GetLanguageType()))
+ {
+ DWARFDeclContext decl_ctx;
+
+ die->GetDWARFDeclContext(this, dwarf_cu, decl_ctx);
+ mangled = decl_ctx.GetQualifiedNameAsConstString().GetCString();
+ }
+ }
+
// 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 variable to see if it contains
@@ -7489,7 +7620,7 @@ SymbolFileDWARF::ParseVariableDIE
{
if (exe_symbol->ValueIsAddress())
{
- const addr_t exe_file_addr = exe_symbol->GetAddress().GetFileAddress();
+ const addr_t exe_file_addr = exe_symbol->GetAddressRef().GetFileAddress();
if (exe_file_addr != LLDB_INVALID_ADDRESS)
{
if (location.Update_DW_OP_addr (exe_file_addr))
@@ -7928,27 +8059,22 @@ SymbolFileDWARF::FindExternalVisibleDeclsByName (void *baton,
}
}
-bool
-SymbolFileDWARF::LayoutRecordType (void *baton,
- const clang::RecordDecl *record_decl,
- uint64_t &size,
- uint64_t &alignment,
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
+bool
+SymbolFileDWARF::LayoutRecordType(void *baton, const clang::RecordDecl *record_decl, uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
{
SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton;
return symbol_file_dwarf->LayoutRecordType (record_decl, size, alignment, field_offsets, base_offsets, vbase_offsets);
}
-
-bool
-SymbolFileDWARF::LayoutRecordType (const clang::RecordDecl *record_decl,
- uint64_t &bit_size,
- uint64_t &alignment,
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
+bool
+SymbolFileDWARF::LayoutRecordType(const clang::RecordDecl *record_decl, uint64_t &bit_size, uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
{
Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
RecordDeclToLayoutMap::iterator pos = m_record_decl_to_layout_map.find (record_decl);
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index d8efdbcb38a4..2f0b3f05b153 100644
--- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -103,6 +103,7 @@ public:
virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc);
virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc);
virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList& support_files);
+ virtual bool ParseImportedModules (const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules);
virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
virtual size_t ParseTypes (const lldb_private::SymbolContext& sc);
virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc);
@@ -151,22 +152,15 @@ public:
clang::DeclarationName Name,
llvm::SmallVectorImpl <clang::NamedDecl *> *results);
- static bool
- LayoutRecordType (void *baton,
- const clang::RecordDecl *record_decl,
- uint64_t &size,
- uint64_t &alignment,
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
-
- bool
- LayoutRecordType (const clang::RecordDecl *record_decl,
- uint64_t &size,
- uint64_t &alignment,
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
+ static bool LayoutRecordType(void *baton, const clang::RecordDecl *record_decl, uint64_t &size, uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
+
+ bool LayoutRecordType(const clang::RecordDecl *record_decl, uint64_t &size, uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
struct LayoutInfo
{
@@ -180,9 +174,9 @@ public:
}
uint64_t bit_size;
uint64_t alignment;
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> field_offsets;
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> base_offsets;
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> vbase_offsets;
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> base_offsets;
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> vbase_offsets;
};
//------------------------------------------------------------------
// PluginInterface protocol
@@ -366,7 +360,6 @@ protected:
bool skip_artificial,
bool &is_static,
bool &is_variadic,
- lldb_private::TypeList* type_list,
std::vector<lldb_private::ClangASTType>& function_args,
std::vector<clang::ParmVarDecl*>& function_param_decls,
unsigned &type_quals);
@@ -393,10 +386,12 @@ protected:
// Given a die_offset, figure out the symbol context representing that die.
bool ResolveFunction (dw_offset_t offset,
DWARFCompileUnit *&dwarf_cu,
+ bool include_inlines,
lldb_private::SymbolContextList& sc_list);
bool ResolveFunction (DWARFCompileUnit *cu,
const DWARFDebugInfoEntry *die,
+ bool include_inlines,
lldb_private::SymbolContextList& sc_list);
bool FunctionDieMatchesPartialName (
@@ -410,16 +405,19 @@ protected:
void FindFunctions(
const lldb_private::ConstString &name,
const NameToDIE &name_to_die,
+ bool include_inlines,
lldb_private::SymbolContextList& sc_list);
void FindFunctions (
const lldb_private::RegularExpression &regex,
const NameToDIE &name_to_die,
+ bool include_inlines,
lldb_private::SymbolContextList& sc_list);
void FindFunctions (
const lldb_private::RegularExpression &regex,
const DWARFMappedHash::MemoryTable &memory_table,
+ bool include_inlines,
lldb_private::SymbolContextList& sc_list);
lldb::TypeSP FindDefinitionTypeForDWARFDeclContext (
@@ -438,6 +436,7 @@ protected:
lldb_private::Symbol * GetObjCClassSymbol (const lldb_private::ConstString &objc_class_name);
void ParseFunctions (const DIEArray &die_offsets,
+ bool include_inlines,
lldb_private::SymbolContextList& sc_list);
lldb::TypeSP GetTypeForDIE (DWARFCompileUnit *cu,
const DWARFDebugInfoEntry* die);
@@ -549,6 +548,13 @@ protected:
FixupAddress (lldb_private::Address &addr);
typedef std::set<lldb_private::Type *> TypeSet;
+
+ typedef struct {
+ lldb_private::ConstString m_name;
+ lldb::ModuleSP m_module_sp;
+ } ClangModuleInfo;
+
+ typedef std::map<uint64_t, ClangModuleInfo> ExternalTypeModuleMap;
void
GetTypes (DWARFCompileUnit* dwarf_cu,
@@ -562,6 +568,9 @@ protected:
GlobalVariableMap &
GetGlobalAranges();
+
+ void
+ UpdateExternalModuleListIfNeeded();
lldb::ModuleWP m_debug_map_module_wp;
SymbolFileDWARFDebugMap * m_debug_map_symfile;
@@ -591,6 +600,7 @@ protected:
std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_namespaces_ap;
std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_objc_ap;
std::unique_ptr<GlobalVariableMap> m_global_aranges_ap;
+ ExternalTypeModuleMap m_external_type_modules;
NameToDIE m_function_basename_index; // All concrete functions
NameToDIE m_function_fullname_index; // All concrete functions
NameToDIE m_function_method_index; // All inlined functions
@@ -601,7 +611,8 @@ protected:
NameToDIE m_namespace_index; // All type DIE offsets
bool m_indexed:1,
m_is_external_ast_source:1,
- m_using_apple_tables:1;
+ m_using_apple_tables:1,
+ m_fetched_external_modules:1;
lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type;
std::unique_ptr<DWARFDebugRanges> m_ranges;
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index af16c03a8c07..5579a23ce716 100644
--- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -121,8 +121,8 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa
{
// Add the inverse OSO file address to debug map entry mapping
exe_symfile->AddOSOFileRange (this,
- exe_symbol->GetAddress().GetFileAddress(),
- oso_fun_symbol->GetAddress().GetFileAddress(),
+ exe_symbol->GetAddressRef().GetFileAddress(),
+ oso_fun_symbol->GetAddressRef().GetFileAddress(),
std::min<addr_t>(exe_symbol->GetByteSize(), oso_fun_symbol->GetByteSize()));
}
@@ -155,8 +155,8 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa
{
// Add the inverse OSO file address to debug map entry mapping
exe_symfile->AddOSOFileRange (this,
- exe_symbol->GetAddress().GetFileAddress(),
- oso_gsym_symbol->GetAddress().GetFileAddress(),
+ exe_symbol->GetAddressRef().GetFileAddress(),
+ oso_gsym_symbol->GetAddressRef().GetFileAddress(),
std::min<addr_t>(exe_symbol->GetByteSize(), oso_gsym_symbol->GetByteSize()));
}
}
@@ -227,18 +227,11 @@ public:
if (exe_objfile && exe_sym_vendor)
{
- if (oso_symfile->GetNumCompileUnits() == 1)
- {
- oso_symfile->SetDebugMapModule(exe_module_sp);
- // Set the ID of the symbol file DWARF to the index of the OSO
- // shifted left by 32 bits to provide a unique prefix for any
- // UserID's that get created in the symbol file.
- oso_symfile->SetID (((uint64_t)m_cu_idx + 1ull) << 32ull);
- }
- else
- {
- oso_symfile->SetID (UINT64_MAX);
- }
+ oso_symfile->SetDebugMapModule(exe_module_sp);
+ // Set the ID of the symbol file DWARF to the index of the OSO
+ // shifted left by 32 bits to provide a unique prefix for any
+ // UserID's that get created in the symbol file.
+ oso_symfile->SetID (((uint64_t)m_cu_idx + 1ull) << 32ull);
}
return symbol_vendor;
}
@@ -381,7 +374,7 @@ SymbolFileDWARFDebugMap::InitOSO()
for (uint32_t sym_idx : m_func_indexes)
{
const Symbol *symbol = symtab->SymbolAtIndex(sym_idx);
- lldb::addr_t file_addr = symbol->GetAddress().GetFileAddress();
+ lldb::addr_t file_addr = symbol->GetAddressRef().GetFileAddress();
lldb::addr_t byte_size = symbol->GetByteSize();
DebugMap::Entry debug_map_entry(file_addr, byte_size, OSOEntry(sym_idx, LLDB_INVALID_ADDRESS));
m_debug_map.Append(debug_map_entry);
@@ -389,7 +382,7 @@ SymbolFileDWARFDebugMap::InitOSO()
for (uint32_t sym_idx : m_glob_indexes)
{
const Symbol *symbol = symtab->SymbolAtIndex(sym_idx);
- lldb::addr_t file_addr = symbol->GetAddress().GetFileAddress();
+ lldb::addr_t file_addr = symbol->GetAddressRef().GetFileAddress();
lldb::addr_t byte_size = symbol->GetByteSize();
DebugMap::Entry debug_map_entry(file_addr, byte_size, OSOEntry(sym_idx, LLDB_INVALID_ADDRESS));
m_debug_map.Append(debug_map_entry);
@@ -412,11 +405,11 @@ SymbolFileDWARFDebugMap::InitOSO()
m_compile_unit_infos[i].so_file.SetFile(so_symbol->GetName().AsCString(), false);
m_compile_unit_infos[i].oso_path = oso_symbol->GetName();
TimeValue oso_mod_time;
- oso_mod_time.OffsetWithSeconds(oso_symbol->GetAddress().GetOffset());
+ oso_mod_time.OffsetWithSeconds(oso_symbol->GetIntegerValue(0));
m_compile_unit_infos[i].oso_mod_time = oso_mod_time;
uint32_t sibling_idx = so_symbol->GetSiblingIndex();
// The sibling index can't be less that or equal to the current index "i"
- if (sibling_idx <= i)
+ if (sibling_idx == UINT32_MAX)
{
m_obj_file->GetModule()->ReportError ("N_SO in symbol with UID %u has invalid sibling in debug map, please file a bug and attach the binary listed in this error", so_symbol->GetID());
}
@@ -743,6 +736,14 @@ SymbolFileDWARFDebugMap::ParseCompileUnitSupportFiles (const SymbolContext& sc,
return false;
}
+bool
+SymbolFileDWARFDebugMap::ParseImportedModules (const SymbolContext &sc, std::vector<ConstString> &imported_modules)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseImportedModules(sc, imported_modules);
+ return false;
+}
size_t
SymbolFileDWARFDebugMap::ParseFunctionBlocks (const SymbolContext& sc)
@@ -909,31 +910,33 @@ SymbolFileDWARFDebugMap::FindGlobalVariables (const ConstString &name, const Cla
const uint32_t original_size = variables.GetSize();
uint32_t total_matches = 0;
- SymbolFileDWARF *oso_dwarf;
- for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
- {
+
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
const uint32_t oso_matches = oso_dwarf->FindGlobalVariables (name,
namespace_decl,
- true,
- max_matches,
+ true,
+ max_matches,
variables);
if (oso_matches > 0)
{
total_matches += oso_matches;
-
+
// Are we getting all matches?
if (max_matches == UINT32_MAX)
- continue; // Yep, continue getting everything
-
+ return false; // Yep, continue getting everything
+
// If we have found enough matches, lets get out
if (max_matches >= total_matches)
- break;
-
+ return true;
+
// Update the max matches for any subsequent calls to find globals
// in any other object files with DWARF
max_matches -= oso_matches;
}
- }
+
+ return false;
+ });
+
// Return the number of variable that were appended to the list
return variables.GetSize() - original_size;
}
@@ -951,10 +954,8 @@ SymbolFileDWARFDebugMap::FindGlobalVariables (const RegularExpression& regex, bo
const uint32_t original_size = variables.GetSize();
uint32_t total_matches = 0;
- SymbolFileDWARF *oso_dwarf;
- for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
- {
- const uint32_t oso_matches = oso_dwarf->FindGlobalVariables (regex,
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
+ const uint32_t oso_matches = oso_dwarf->FindGlobalVariables (regex,
true,
max_matches,
variables);
@@ -964,17 +965,20 @@ SymbolFileDWARFDebugMap::FindGlobalVariables (const RegularExpression& regex, bo
// Are we getting all matches?
if (max_matches == UINT32_MAX)
- continue; // Yep, continue getting everything
+ return false; // Yep, continue getting everything
// If we have found enough matches, lets get out
if (max_matches >= total_matches)
- break;
+ return true;
// Update the max matches for any subsequent calls to find globals
// in any other object files with DWARF
max_matches -= oso_matches;
}
- }
+
+ return false;
+ });
+
// Return the number of variable that were appended to the list
return variables.GetSize() - original_size;
}
@@ -1099,16 +1103,14 @@ SymbolFileDWARFDebugMap::FindFunctions(const ConstString &name, const ClangNames
else
sc_list.Clear();
- uint32_t oso_idx = 0;
- SymbolFileDWARF *oso_dwarf;
- while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
- {
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
uint32_t sc_idx = sc_list.GetSize();
if (oso_dwarf->FindFunctions(name, namespace_decl, name_type_mask, include_inlines, true, sc_list))
{
RemoveFunctionsWithModuleNotEqualTo (m_obj_file->GetModule(), sc_list, sc_idx);
}
- }
+ return false;
+ });
return sc_list.GetSize() - initial_size;
}
@@ -1127,17 +1129,15 @@ SymbolFileDWARFDebugMap::FindFunctions (const RegularExpression& regex, bool inc
else
sc_list.Clear();
- uint32_t oso_idx = 0;
- SymbolFileDWARF *oso_dwarf;
- while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
- {
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
uint32_t sc_idx = sc_list.GetSize();
if (oso_dwarf->FindFunctions(regex, include_inlines, true, sc_list))
{
RemoveFunctionsWithModuleNotEqualTo (m_obj_file->GetModule(), sc_list, sc_idx);
}
- }
+ return false;
+ });
return sc_list.GetSize() - initial_size;
}
@@ -1169,11 +1169,10 @@ SymbolFileDWARFDebugMap::GetTypes (SymbolContextScope *sc_scope,
}
else
{
- uint32_t oso_idx = 0;
- while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
- {
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
oso_dwarf->GetTypes (sc_scope, type_mask, type_list);
- }
+ return false;
+ });
}
return type_list.GetSize() - initial_size;
}
@@ -1183,13 +1182,10 @@ TypeSP
SymbolFileDWARFDebugMap::FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &die_decl_ctx)
{
TypeSP type_sp;
- SymbolFileDWARF *oso_dwarf;
- for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
- {
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
type_sp = oso_dwarf->FindDefinitionTypeForDWARFDeclContext (die_decl_ctx);
- if (type_sp)
- break;
- }
+ return ((bool)type_sp);
+ });
return type_sp;
}
@@ -1201,15 +1197,14 @@ SymbolFileDWARFDebugMap::Supports_DW_AT_APPLE_objc_complete_type (SymbolFileDWAR
if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate)
{
m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo;
- SymbolFileDWARF *oso_dwarf;
- for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
- {
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
if (skip_dwarf_oso != oso_dwarf && oso_dwarf->Supports_DW_AT_APPLE_objc_complete_type(NULL))
{
m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
- break;
+ return true;
}
- }
+ return false;
+ });
}
return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes;
}
@@ -1219,15 +1214,65 @@ SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugI
const ConstString &type_name,
bool must_be_implementation)
{
+ // If we have a debug map, we will have an Objective C symbol whose name is
+ // the type name and whose type is eSymbolTypeObjCClass. If we can find that
+ // symbol and find its containing parent, we can locate the .o file that will
+ // contain the implementation definition since it will be scoped inside the N_SO
+ // and we can then locate the SymbolFileDWARF that corresponds to that N_SO.
+ SymbolFileDWARF *oso_dwarf = NULL;
TypeSP type_sp;
- SymbolFileDWARF *oso_dwarf;
- for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ ObjectFile *module_objfile = m_obj_file->GetModule()->GetObjectFile();
+ if (module_objfile)
{
- type_sp = oso_dwarf->FindCompleteObjCDefinitionTypeForDIE (die, type_name, must_be_implementation);
- if (type_sp)
- break;
+ Symtab *symtab = module_objfile->GetSymtab();
+ if (symtab)
+ {
+ Symbol *objc_class_symbol = symtab->FindFirstSymbolWithNameAndType(type_name, eSymbolTypeObjCClass, Symtab::eDebugAny, Symtab::eVisibilityAny);
+ if (objc_class_symbol)
+ {
+ // Get the N_SO symbol that contains the objective C class symbol as this
+ // should be the .o file that contains the real definition...
+ const Symbol *source_file_symbol = symtab->GetParent(objc_class_symbol);
+
+ if (source_file_symbol && source_file_symbol->GetType() == eSymbolTypeSourceFile)
+ {
+ const uint32_t source_file_symbol_idx = symtab->GetIndexForSymbol(source_file_symbol);
+ if (source_file_symbol_idx != UINT32_MAX)
+ {
+ CompileUnitInfo *compile_unit_info = GetCompileUnitInfoForSymbolWithIndex (source_file_symbol_idx, NULL);
+ if (compile_unit_info)
+ {
+ oso_dwarf = GetSymbolFileByCompUnitInfo (compile_unit_info);
+ if (oso_dwarf)
+ {
+ TypeSP type_sp (oso_dwarf->FindCompleteObjCDefinitionTypeForDIE (die, type_name, must_be_implementation));
+ if (type_sp)
+ {
+ return type_sp;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
- return type_sp;
+
+ // Only search all .o files for the definition if we don't need the implementation
+ // because otherwise, with a valid debug map we should have the ObjC class symbol and
+ // the code above should have found it.
+ if (must_be_implementation == false)
+ {
+ TypeSP type_sp;
+
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
+ type_sp = oso_dwarf->FindCompleteObjCDefinitionTypeForDIE (die, type_name, must_be_implementation);
+ return (bool)type_sp;
+ });
+
+ return type_sp;
+ }
+ return TypeSP();
}
uint32_t
@@ -1255,9 +1300,10 @@ SymbolFileDWARFDebugMap::FindTypes
}
else
{
- uint32_t oso_idx = 0;
- while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
oso_dwarf->FindTypes (sc, name, namespace_decl, append, max_matches, types);
+ return false;
+ });
}
return types.GetSize() - initial_types_size;
@@ -1290,15 +1336,11 @@ SymbolFileDWARFDebugMap::FindNamespace (const lldb_private::SymbolContext& sc,
}
else
{
- for (uint32_t oso_idx = 0;
- ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL);
- ++oso_idx)
- {
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
matching_namespace = oso_dwarf->FindNamespace (sc, name, parent_namespace_decl);
- if (matching_namespace)
- break;
- }
+ return (bool)matching_namespace;
+ });
}
return matching_namespace;
@@ -1393,16 +1435,14 @@ SymbolFileDWARFDebugMap::CompleteTagDecl (void *baton, clang::TagDecl *decl)
ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl);
if (clang_type)
{
- SymbolFileDWARF *oso_dwarf;
-
- for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
- {
+ symbol_file_dwarf->ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
if (oso_dwarf->HasForwardDeclForClangType (clang_type))
{
oso_dwarf->ResolveClangOpaqueTypeDefinition (clang_type);
- return;
+ return true;
}
- }
+ return false;
+ });
}
}
@@ -1413,36 +1453,30 @@ SymbolFileDWARFDebugMap::CompleteObjCInterfaceDecl (void *baton, clang::ObjCInte
ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl);
if (clang_type)
{
- SymbolFileDWARF *oso_dwarf;
-
- for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
- {
+ symbol_file_dwarf->ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
if (oso_dwarf->HasForwardDeclForClangType (clang_type))
{
oso_dwarf->ResolveClangOpaqueTypeDefinition (clang_type);
- return;
+ return true;
}
- }
+ return false;
+ });
}
}
-bool
-SymbolFileDWARFDebugMap::LayoutRecordType (void *baton,
- const clang::RecordDecl *record_decl,
- uint64_t &size,
- uint64_t &alignment,
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
+bool
+SymbolFileDWARFDebugMap::LayoutRecordType(void *baton, const clang::RecordDecl *record_decl, uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
{
SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton;
- SymbolFileDWARF *oso_dwarf;
- for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
- {
- if (oso_dwarf->LayoutRecordType (record_decl, size, alignment, field_offsets, base_offsets, vbase_offsets))
- return true;
- }
- return false;
+ bool laid_out = false;
+ symbol_file_dwarf->ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
+ return (laid_out = oso_dwarf->LayoutRecordType (record_decl, size, alignment, field_offsets, base_offsets, vbase_offsets));
+ });
+ return laid_out;
}
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index 1493292d4b9b..ce0cfd744f0b 100644
--- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -53,45 +53,46 @@ public:
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
- SymbolFileDWARFDebugMap (lldb_private::ObjectFile* ofile);
- virtual ~ SymbolFileDWARFDebugMap ();
+ SymbolFileDWARFDebugMap (lldb_private::ObjectFile* ofile);
+ ~SymbolFileDWARFDebugMap () override;
- virtual uint32_t CalculateAbilities ();
+ uint32_t CalculateAbilities () override;
- virtual void InitializeObject();
+ void InitializeObject() override;
//------------------------------------------------------------------
// Compile Unit function calls
//------------------------------------------------------------------
- virtual uint32_t GetNumCompileUnits ();
- virtual lldb::CompUnitSP ParseCompileUnitAtIndex (uint32_t index);
-
- virtual lldb::LanguageType ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc);
- virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc);
- virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc);
- virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files);
- virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
- virtual size_t ParseTypes (const lldb_private::SymbolContext& sc);
- virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc);
-
- virtual lldb_private::Type* ResolveTypeUID (lldb::user_id_t type_uid);
- virtual clang::DeclContext* GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid);
- virtual clang::DeclContext* GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid);
- virtual bool ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_type);
- virtual uint32_t ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc);
- virtual uint32_t ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list);
- virtual uint32_t FindGlobalVariables (const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
- virtual uint32_t FindGlobalVariables (const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
- virtual uint32_t FindFunctions (const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
- virtual uint32_t FindFunctions (const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
- virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::TypeList& types);
- virtual lldb_private::ClangNamespaceDecl
- FindNamespace (const lldb_private::SymbolContext& sc,
- const lldb_private::ConstString &name,
- const lldb_private::ClangNamespaceDecl *parent_namespace_decl);
- virtual size_t GetTypes (lldb_private::SymbolContextScope *sc_scope,
- uint32_t type_mask,
- lldb_private::TypeList &type_list);
+ uint32_t GetNumCompileUnits () override;
+ lldb::CompUnitSP ParseCompileUnitAtIndex (uint32_t index) override;
+
+ lldb::LanguageType ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc) override;
+ size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc) override;
+ bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc) override;
+ bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files) override;
+ bool ParseImportedModules (const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules) override;
+ size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc) override;
+ size_t ParseTypes (const lldb_private::SymbolContext& sc) override;
+ size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc) override;
+
+ lldb_private::Type* ResolveTypeUID (lldb::user_id_t type_uid) override;
+ clang::DeclContext* GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid) override;
+ clang::DeclContext* GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid) override;
+ bool ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_type) override;
+ uint32_t ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc) override;
+ uint32_t ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list) override;
+ uint32_t FindGlobalVariables (const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::VariableList& variables) override;
+ uint32_t FindGlobalVariables (const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables) override;
+ uint32_t FindFunctions (const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list) override;
+ uint32_t FindFunctions (const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list) override;
+ uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::TypeList& types) override;
+ lldb_private::ClangNamespaceDecl
+ FindNamespace (const lldb_private::SymbolContext& sc,
+ const lldb_private::ConstString &name,
+ const lldb_private::ClangNamespaceDecl *parent_namespace_decl) override;
+ size_t GetTypes (lldb_private::SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ lldb_private::TypeList &type_list) override;
//------------------------------------------------------------------
@@ -102,25 +103,20 @@ public:
static void
CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *);
-
- static bool
- LayoutRecordType (void *baton,
- const clang::RecordDecl *record_decl,
- uint64_t &size,
- uint64_t &alignment,
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
+ static bool LayoutRecordType(void *baton, const clang::RecordDecl *record_decl, uint64_t &size, uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
- virtual lldb_private::ConstString
- GetPluginName();
+ lldb_private::ConstString
+ GetPluginName() override;
- virtual uint32_t
- GetPluginVersion();
+ uint32_t
+ GetPluginVersion() override;
protected:
enum
@@ -231,6 +227,23 @@ protected:
SymbolFileDWARF *
GetSymbolFileByOSOIndex (uint32_t oso_idx);
+
+ // If closure returns "false", iteration continues. If it returns
+ // "true", iteration terminates.
+ void
+ ForEachSymbolFile (std::function<bool (SymbolFileDWARF *)> closure)
+ {
+ for (uint32_t oso_idx = 0, num_oso_idxs = m_compile_unit_infos.size();
+ oso_idx < num_oso_idxs;
+ ++oso_idx)
+ {
+ if (SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx))
+ {
+ if (closure(oso_dwarf))
+ return;
+ }
+ }
+ }
CompileUnitInfo *
GetCompileUnitInfoForSymbolWithIndex (uint32_t symbol_idx, uint32_t *oso_idx_ptr);
diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
index 8e85d4825281..64c88ab716bf 100644
--- a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
+++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
@@ -225,7 +225,7 @@ SymbolFileSymtab::ParseCompileUnitFunctions (const SymbolContext &sc)
next_symbol = symtab->SymbolAtIndex(m_code_indexes[idx + 1]);
if (next_symbol)
{
- func_range.SetByteSize(next_symbol->GetAddress().GetOffset() - curr_symbol->GetAddress().GetOffset());
+ func_range.SetByteSize(next_symbol->GetAddressRef().GetOffset() - curr_symbol->GetAddressRef().GetOffset());
}
}
@@ -266,6 +266,12 @@ SymbolFileSymtab::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpe
return false;
}
+bool
+SymbolFileSymtab::ParseImportedModules (const SymbolContext &sc, std::vector<ConstString> &imported_modules)
+{
+ return false;
+}
+
size_t
SymbolFileSymtab::ParseFunctionBlocks (const SymbolContext &sc)
{
diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
index 914efe6eb3c2..d606419a0d94 100644
--- a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
+++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
@@ -65,6 +65,9 @@ public:
virtual bool
ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files);
+
+ virtual bool
+ ParseImportedModules (const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules);
virtual size_t
ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
index 0eb0f83d5f35..8f5d92697501 100644
--- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -96,7 +96,13 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
if (num_instructions > 0)
{
Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
- const addr_t base_addr = inst->GetAddress().GetFileAddress();
+ const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();
+
+ // Map for storing the unwind plan row and the value of the registers at a given offset.
+ // When we see a forward branch we add a new entry to this map with the actual unwind plan
+ // row and register context for the target address of the branch as the current data have
+ // to be valid for the target address of the branch too if we are in the same function.
+ std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>> saved_unwind_states;
// Make a copy of the current instruction Row and save it in m_curr_row
// so we can add updates as we process the instructions.
@@ -106,18 +112,8 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
*newrow = *last_row.get();
m_curr_row.reset(newrow);
- // Once we've seen the initial prologue instructions complete, save a
- // copy of the CFI at that point into prologue_completed_row for possible
- // use later.
- int instructions_since_last_prologue_insn = 0; // # of insns since last CFI was update
-
- bool reinstate_prologue_next_instruction = false; // Next iteration, re-install the prologue row of CFI
-
- bool last_instruction_restored_return_addr_reg = false; // re-install the prologue row of CFI if the next instruction is a branch immediate
-
- bool return_address_register_has_been_saved = false; // if we've seen the ra register get saved yet
-
- UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
+ // Add the initial state to the save list with offset 0.
+ saved_unwind_states.insert({0, {last_row, m_register_values}});
// cache the pc register number (in whatever register numbering this UnwindPlan uses) for
// quick reference during instruction parsing.
@@ -140,16 +136,33 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
for (size_t idx=0; idx<num_instructions; ++idx)
{
m_curr_row_modified = false;
- m_curr_insn_restored_a_register = false;
+ m_forward_branch_offset = 0;
+
inst = inst_list.GetInstructionAtIndex (idx).get();
if (inst)
{
+ lldb::addr_t current_offset = inst->GetAddress().GetFileAddress() - base_addr;
+ auto it = saved_unwind_states.upper_bound(current_offset);
+ assert(it != saved_unwind_states.begin() && "Unwind row for the function entry missing");
+ --it; // Move it to the row corresponding to the current offset
+
+ // If the offset of m_curr_row don't match with the offset we see in saved_unwind_states
+ // then we have to update m_curr_row and m_register_values based on the saved values. It
+ // is happenning after we processed an epilogue and a return to caller instruction.
+ if (it->second.first->GetOffset() != m_curr_row->GetOffset())
+ {
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *it->second.first;
+ m_curr_row.reset(newrow);
+ m_register_values = it->second.second;;
+ }
+
if (log && log->GetVerbose ())
{
StreamString strm;
lldb_private::FormatEntity::Entry format;
FormatEntity::Parse("${frame.pc}: ", format);
- inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL, NULL, NULL, &format);
+ inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL, NULL, NULL, &format, 0);
log->PutCString (strm.GetData());
}
@@ -159,111 +172,30 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);
+ // If the current instruction is a branch forward then save the current CFI information
+ // for the offset where we are branching.
+ if (m_forward_branch_offset != 0 && range.ContainsFileAddress(inst->GetAddress().GetFileAddress() + m_forward_branch_offset))
+ {
+ auto newrow = std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
+ newrow->SetOffset(current_offset + m_forward_branch_offset);
+ saved_unwind_states.insert({current_offset + m_forward_branch_offset, {newrow, m_register_values}});
+ unwind_plan.InsertRow(newrow);
+ }
+
// Were there any changes to the CFI while evaluating this instruction?
if (m_curr_row_modified)
{
- reinstate_prologue_next_instruction = false;
- m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
- // Append the new row
- unwind_plan.AppendRow (m_curr_row);
-
- // Allocate a new Row for m_curr_row, copy the current state into it
- UnwindPlan::Row *newrow = new UnwindPlan::Row;
- *newrow = *m_curr_row.get();
- m_curr_row.reset(newrow);
-
- // If m_curr_insn_restored_a_register == true, we're looking at an epilogue instruction.
- // Set instructions_since_last_prologue_insn to a very high number so we don't append
- // any of these epilogue instructions to our prologue_complete row.
- if (m_curr_insn_restored_a_register == false && instructions_since_last_prologue_insn < 8)
- instructions_since_last_prologue_insn = 0;
- else
- instructions_since_last_prologue_insn = 99;
-
- UnwindPlan::Row::RegisterLocation pc_regloc;
- UnwindPlan::Row::RegisterLocation ra_regloc;
-
- // 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 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)
- && !ra_regloc.IsSame())
+ // Save the modified row if we don't already have a CFI row in the currennt address
+ if (saved_unwind_states.count(current_offset + inst->GetOpcode().GetByteSize()) == 0)
{
- return_address_register_has_been_saved = true;
- }
+ m_curr_row->SetOffset (current_offset + inst->GetOpcode().GetByteSize());
+ unwind_plan.InsertRow (m_curr_row);
+ saved_unwind_states.insert({current_offset + inst->GetOpcode().GetByteSize(), {m_curr_row, m_register_values}});
- // If the caller's pc is "same", we've just executed an epilogue and we return to the caller
- // after this instruction completes executing.
- // If there are any instructions past this, there must have been flow control over this
- // epilogue so we'll reinstate the original prologue setup instructions.
- if (prologue_completed_row.get()
- && pc_reg_num != LLDB_INVALID_REGNUM
- && m_curr_row->GetRegisterInfo (pc_reg_num, pc_regloc)
- && pc_regloc.IsSame())
- {
- if (log && log->GetVerbose())
- log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- pc is <same>, restore prologue instructions.");
- reinstate_prologue_next_instruction = true;
- }
- else if (prologue_completed_row.get()
- && return_address_register_has_been_saved
- && ra_reg_num != LLDB_INVALID_REGNUM
- && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
- && ra_regloc.IsSame())
- {
- if (log && log->GetVerbose())
- log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- lr is <same>, restore prologue instruction if the next instruction is a branch immediate.");
- last_instruction_restored_return_addr_reg = true;
- }
- }
- else
- {
- // If the previous instruction was a return-to-caller (epilogue), and we're still executing
- // instructions in this function, there must be a code path that jumps over that epilogue.
- // Also detect the case where we epilogue & branch imm to another function (tail-call opt)
- // instead of a normal pop lr-into-pc exit.
- // Reinstate the frame setup from the prologue.
- if (reinstate_prologue_next_instruction
- || (m_curr_insn_is_branch_immediate && last_instruction_restored_return_addr_reg))
- {
- if (log && log->GetVerbose())
- log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- Reinstating prologue instruction set");
+ // Allocate a new Row for m_curr_row, copy the current state into it
UnwindPlan::Row *newrow = new UnwindPlan::Row;
- *newrow = *prologue_completed_row.get();
- m_curr_row.reset(newrow);
- m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
- unwind_plan.AppendRow(m_curr_row);
-
- newrow = new UnwindPlan::Row;
*newrow = *m_curr_row.get();
m_curr_row.reset(newrow);
-
- reinstate_prologue_next_instruction = false;
- last_instruction_restored_return_addr_reg = false;
- m_curr_insn_is_branch_immediate = false;
- }
-
- // clear both of these if either one wasn't set
- if (last_instruction_restored_return_addr_reg)
- {
- last_instruction_restored_return_addr_reg = false;
- }
- if (m_curr_insn_is_branch_immediate)
- {
- m_curr_insn_is_branch_immediate = false;
- }
-
- // Stop updating the prologue instructions if we've seen 8 non-prologue instructions
- // in a row.
- if (instructions_since_last_prologue_insn++ < 8)
- {
- UnwindPlan::Row *newrow = new UnwindPlan::Row;
- *newrow = *m_curr_row.get();
- prologue_completed_row.reset(newrow);
- if (log && log->GetVerbose())
- log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- saving a copy of the current row as the prologue row.");
}
}
}
@@ -460,8 +392,7 @@ UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
context.Dump(strm, instruction);
log->PutCString (strm.GetData());
}
-
- const bool can_replace = true;
+
const bool cant_replace = false;
switch (context.type)
@@ -491,20 +422,17 @@ UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
case EmulateInstruction::eContextPushRegisterOnStack:
{
uint32_t reg_num = LLDB_INVALID_REGNUM;
- bool is_return_address_reg = false;
- const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
+ uint32_t generic_regnum = LLDB_INVALID_REGNUM;
if (context.info_type == EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset)
{
+ const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
reg_num = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[unwind_reg_kind];
- if (context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA)
- is_return_address_reg = true;
+ generic_regnum = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric];
}
else
- {
assert (!"unhandled case, add code to handle this!");
- }
-
- if (reg_num != LLDB_INVALID_REGNUM)
+
+ if (reg_num != LLDB_INVALID_REGNUM && generic_regnum != LLDB_REGNUM_GENERIC_SP)
{
if (m_pushed_regs.find (reg_num) == m_pushed_regs.end())
{
@@ -512,21 +440,6 @@ UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
const int32_t offset = addr - m_initial_sp;
m_curr_row->SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace);
m_curr_row_modified = true;
- if (is_return_address_reg)
- {
- // This push was pushing the return address register,
- // so this is also how we will unwind the PC...
- RegisterInfo pc_reg_info;
- if (instruction->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
- {
- uint32_t pc_reg_num = pc_reg_info.kinds[unwind_reg_kind];
- if (pc_reg_num != LLDB_INVALID_REGNUM)
- {
- m_curr_row->SetRegisterLocationToAtCFAPlusOffset (pc_reg_num, offset, can_replace);
- m_curr_row_modified = true;
- }
- }
- }
}
}
}
@@ -598,7 +511,6 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
log->PutCString(strm.GetData());
}
- const bool must_replace = true;
SetRegisterValue (*reg_info, reg_value);
switch (context.type)
@@ -610,8 +522,6 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
case EmulateInstruction::eContextRegisterPlusOffset:
case EmulateInstruction::eContextAdjustPC:
case EmulateInstruction::eContextRegisterStore:
- case EmulateInstruction::eContextRegisterLoad:
- case EmulateInstruction::eContextAbsoluteBranchRegister:
case EmulateInstruction::eContextSupervisorCall:
case EmulateInstruction::eContextTableBranchReadMemory:
case EmulateInstruction::eContextWriteRegisterRandomBits:
@@ -620,6 +530,7 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
case EmulateInstruction::eContextAdvancePC:
case EmulateInstruction::eContextReturnFromException:
case EmulateInstruction::eContextPushRegisterOnStack:
+ case EmulateInstruction::eContextRegisterLoad:
// {
// const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
// if (reg_num != LLDB_INVALID_REGNUM)
@@ -634,11 +545,28 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
// }
break;
+ case EmulateInstruction::eContextAbsoluteBranchRegister:
case EmulateInstruction::eContextRelativeBranchImmediate:
{
-
+ if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediate &&
+ context.info.ISAAndImmediate.unsigned_data32 > 0)
+ {
+ m_forward_branch_offset = context.info.ISAAndImmediateSigned.signed_data32;
+ }
+ else if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
+ context.info.ISAAndImmediateSigned.signed_data32 > 0)
+ {
+ m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
+ }
+ else if (context.info_type == EmulateInstruction::eInfoTypeImmediate &&
+ context.info.unsigned_immediate > 0)
+ {
+ m_forward_branch_offset = context.info.unsigned_immediate;
+ }
+ else if (context.info_type == EmulateInstruction::eInfoTypeImmediateSigned &&
+ context.info.signed_immediate > 0)
{
- m_curr_insn_is_branch_immediate = true;
+ m_forward_branch_offset = context.info.signed_immediate;
}
}
break;
@@ -646,11 +574,11 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
case EmulateInstruction::eContextPopRegisterOffStack:
{
const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
- if (reg_num != LLDB_INVALID_REGNUM)
+ const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_num != LLDB_INVALID_REGNUM && generic_regnum != LLDB_REGNUM_GENERIC_SP)
{
- m_curr_row->SetRegisterLocationToSame (reg_num, must_replace);
+ m_curr_row->SetRegisterLocationToSame (reg_num, /*must_replace*/ false);
m_curr_row_modified = true;
- m_curr_insn_restored_a_register = true;
}
}
break;
@@ -662,8 +590,8 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
m_cfa_reg_info = *reg_info;
const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
assert (cfa_reg_num != LLDB_INVALID_REGNUM);
- m_curr_row->SetCFARegister(cfa_reg_num);
- m_curr_row->SetCFAOffset(m_initial_sp - reg_value.GetAsUInt64());
+ m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(cfa_reg_num, m_initial_sp -
+ reg_value.GetAsUInt64());
m_curr_row_modified = true;
}
break;
@@ -673,7 +601,9 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
// subsequent adjustments to the stack pointer.
if (!m_fp_is_cfa)
{
- m_curr_row->SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64());
+ m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
+ m_curr_row->GetCFAValue().GetRegisterNumber(),
+ m_initial_sp - reg_value.GetAsUInt64());
m_curr_row_modified = true;
}
break;
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
index 758c3ce2e28b..bf6d017370cc 100644
--- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
@@ -141,8 +141,7 @@ private:
m_register_values (),
m_pushed_regs(),
m_curr_row_modified (false),
- m_curr_insn_is_branch_immediate (false),
- m_curr_insn_restored_a_register (false)
+ m_forward_branch_offset (0)
{
if (m_inst_emulator_ap.get())
{
@@ -178,13 +177,11 @@ private:
// While processing the instruction stream, we need to communicate some state change
// information up to the higher level loop that makes decisions about how to push
// the unwind instructions for the UnwindPlan we're constructing.
-
+
// The instruction we're processing updated the UnwindPlan::Row contents
bool m_curr_row_modified;
- // The instruction we're examining is a branch immediate instruction
- bool m_curr_insn_is_branch_immediate;
- // The instruction we're processing restored a caller's reg value (e.g. in an epilogue)
- bool m_curr_insn_restored_a_register;
+ // The instruction is branching forward with the given offset. 0 value means no branching.
+ uint32_t m_forward_branch_offset;
};
#endif // liblldb_UnwindAssemblyInstEmulation_h_
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
index dbf37d8a4de0..7e4c696a36d4 100644
--- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -10,6 +10,7 @@
#include "UnwindAssembly-x86.h"
#include "llvm-c/Disassembler.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/TargetSelect.h"
#include "lldb/Core/Address.h"
@@ -17,6 +18,7 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -146,6 +148,7 @@ private:
bool mov_rsp_rbp_pattern_p ();
bool sub_rsp_pattern_p (int& amount);
bool add_rsp_pattern_p (int& amount);
+ bool lea_rsp_pattern_p (int& amount);
bool push_reg_p (int& regno);
bool pop_reg_p (int& regno);
bool push_imm_pattern_p ();
@@ -408,6 +411,36 @@ AssemblyParse_x86::add_rsp_pattern_p (int& amount)
return false;
}
+// lea esp, [esp - 0x28]
+// lea esp, [esp + 0x28]
+bool
+AssemblyParse_x86::lea_rsp_pattern_p (int& amount)
+{
+ uint8_t *p = m_cur_insn_bytes;
+ if (m_wordsize == 8 && *p == 0x48)
+ p++;
+
+ // Check opcode
+ if (*p != 0x8d)
+ return false;
+
+ // 8 bit displacement
+ if (*(p + 1) == 0x64 && (*(p + 2) & 0x3f) == 0x24)
+ {
+ amount = (int8_t) *(p + 3);
+ return true;
+ }
+
+ // 32 bit displacement
+ if (*(p + 1) == 0xa4 && (*(p + 2) & 0x3f) == 0x24)
+ {
+ amount = (int32_t) extract_4 (p + 3);
+ return true;
+ }
+
+ return false;
+}
+
// pushq %rbx
// pushl %ebx
bool
@@ -615,7 +648,7 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
{
UnwindPlan::RowSP row(new UnwindPlan::Row);
m_cur_insn = m_func_bounds.GetBaseAddress ();
- int current_func_text_offset = 0;
+ addr_t current_func_text_offset = 0;
int current_sp_bytes_offset_from_cfa = 0;
UnwindPlan::Row::RegisterLocation initial_regloc;
Error error;
@@ -630,8 +663,7 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
// At the start of the function, find the CFA by adding wordsize to the SP register
row->SetOffset (current_func_text_offset);
- row->SetCFARegister (m_lldb_sp_regnum);
- row->SetCFAOffset (m_wordsize);
+ row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, m_wordsize);
// caller's stack pointer value before the call insn is the CFA address
initial_regloc.SetIsCFAPlusOffset (0);
@@ -691,9 +723,9 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
if (push_rbp_pattern_p ())
{
current_sp_bytes_offset_from_cfa += m_wordsize;
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
UnwindPlan::Row::RegisterLocation regloc;
- regloc.SetAtCFAPlusOffset (-row->GetCFAOffset());
+ regloc.SetAtCFAPlusOffset (-row->GetCFAValue().GetOffset());
row->SetRegisterInfo (m_lldb_fp_regnum, regloc);
saved_registers[m_machine_fp_regnum] = true;
row_updated = true;
@@ -701,7 +733,7 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
else if (mov_rsp_rbp_pattern_p ())
{
- row->SetCFARegister (m_lldb_fp_regnum);
+ row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_fp_regnum, row->GetCFAValue().GetOffset());
row_updated = true;
}
@@ -717,9 +749,9 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
current_sp_bytes_offset_from_cfa += m_wordsize;
// the PUSH instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer,
// we need to add a new row of instructions.
- if (row->GetCFARegister() == m_lldb_sp_regnum)
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
{
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
row_updated = true;
}
// record where non-volatile (callee-saved, spilled) registers are saved on the stack
@@ -746,9 +778,10 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
saved_registers[machine_regno] = false;
row->RemoveRegisterInfo (lldb_regno);
- if (machine_regno == m_machine_fp_regnum)
+ if (machine_regno == (int)m_machine_fp_regnum)
{
- row->SetCFARegister (m_lldb_sp_regnum);
+ row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum,
+ row->GetCFAValue().GetOffset());
}
in_epilogue = true;
@@ -757,9 +790,10 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
// the POP instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer,
// we need to add a new row of instructions.
- if (row->GetCFARegister() == m_lldb_sp_regnum)
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
{
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum,
+ current_sp_bytes_offset_from_cfa);
row_updated = true;
}
}
@@ -777,7 +811,7 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
// 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()));
+ regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAValue().GetOffset()));
row->SetRegisterInfo (lldb_regno, regloc);
@@ -787,9 +821,9 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
else if (sub_rsp_pattern_p (stack_offset))
{
current_sp_bytes_offset_from_cfa += stack_offset;
- if (row->GetCFARegister() == m_lldb_sp_regnum)
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
{
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
row_updated = true;
}
}
@@ -797,14 +831,26 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
else if (add_rsp_pattern_p (stack_offset))
{
current_sp_bytes_offset_from_cfa -= stack_offset;
- if (row->GetCFARegister() == m_lldb_sp_regnum)
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
{
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
row_updated = true;
}
in_epilogue = true;
}
+ else if (lea_rsp_pattern_p (stack_offset))
+ {
+ current_sp_bytes_offset_from_cfa -= stack_offset;
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
+ {
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
+ row_updated = true;
+ }
+ if (stack_offset > 0)
+ in_epilogue = true;
+ }
+
else if (ret_pattern_p () && prologue_completed_row.get())
{
// Reinstate the saved prologue setup for any instructions
@@ -833,9 +879,9 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
else if (call_next_insn_pattern_p ())
{
current_sp_bytes_offset_from_cfa += m_wordsize;
- if (row->GetCFARegister() == m_lldb_sp_regnum)
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
{
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
row_updated = true;
}
}
@@ -904,8 +950,8 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
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)
+ first_row->GetCFAValue().GetRegisterNumber());
+ if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAValue().GetOffset() != m_wordsize)
return false;
UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset (-1);
@@ -985,7 +1031,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
// 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());
+ row->GetCFAValue().GetRegisterNumber());
if (cfa_reg == m_lldb_sp_regnum)
{
// CFA register is sp.
@@ -996,7 +1042,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (call_next_insn_pattern_p ())
{
row->SetOffset (offset);
- row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (m_wordsize);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
@@ -1009,7 +1055,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (push_reg_p (regno))
{
row->SetOffset (offset);
- row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (m_wordsize);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
@@ -1024,7 +1070,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
// So we ignore this case.
row->SetOffset (offset);
- row->SetCFAOffset (-m_wordsize + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (-m_wordsize);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
@@ -1036,7 +1082,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (push_imm_pattern_p ())
{
row->SetOffset (offset);
- row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (m_wordsize);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
unwind_plan_updated = true;
@@ -1048,7 +1094,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (add_rsp_pattern_p (amount))
{
row->SetOffset (offset);
- row->SetCFAOffset (-amount + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (-amount);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
@@ -1058,13 +1104,26 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (sub_rsp_pattern_p (amount))
{
row->SetOffset (offset);
- row->SetCFAOffset (amount + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (amount);
+
+ UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+ unwind_plan.InsertRow (new_row);
+ unwind_plan_updated = true;
+ continue;
+ }
+
+ // lea %rsp, [%rsp + $offset]
+ if (lea_rsp_pattern_p (amount))
+ {
+ row->SetOffset (offset);
+ row->GetCFAValue().IncOffset (-amount);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
unwind_plan_updated = true;
continue;
}
+
if (ret_pattern_p ())
{
reinstate_unwind_state = true;
@@ -1085,8 +1144,8 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
&& ret_pattern_p ())
{
row->SetOffset (offset);
- row->SetCFARegister (first_row->GetCFARegister());
- row->SetCFAOffset (m_wordsize);
+ row->GetCFAValue().SetIsRegisterPlusOffset (
+ first_row->GetCFAValue().GetRegisterNumber(), m_wordsize);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
@@ -1169,8 +1228,7 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_
row->SetRegisterInfo (m_lldb_sp_regnum, sp_reginfo);
// Zero instructions into the function
- row->SetCFARegister (m_lldb_sp_regnum);
- row->SetCFAOffset (m_wordsize);
+ row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum, m_wordsize);
row->SetOffset (0);
unwind_plan.AppendRow (row);
UnwindPlan::Row *newrow = new UnwindPlan::Row;
@@ -1178,7 +1236,7 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_
row.reset(newrow);
// push %rbp has executed - stack moved, rbp now saved
- row->SetCFAOffset (2 * m_wordsize);
+ row->GetCFAValue().IncOffset (m_wordsize);
fp_reginfo.SetAtCFAPlusOffset (2 * -m_wordsize);
row->SetRegisterInfo (m_lldb_fp_regnum, fp_reginfo);
row->SetOffset (1);
@@ -1189,8 +1247,7 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_
row.reset(newrow);
// mov %rsp, %rbp has executed
- row->SetCFARegister (m_lldb_fp_regnum);
- row->SetCFAOffset (2 * m_wordsize);
+ row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_fp_regnum, 2 * m_wordsize);
row->SetOffset (prologue_size); /// 3 or 4 bytes depending on arch
unwind_plan.AppendRow (row);
@@ -1233,7 +1290,8 @@ AssemblyParse_x86::find_first_non_prologue_insn (Address &address)
}
if (push_rbp_pattern_p () || mov_rsp_rbp_pattern_p () || sub_rsp_pattern_p (offset)
- || push_reg_p (regno) || mov_reg_to_local_stack_frame_p (regno, offset))
+ || push_reg_p (regno) || mov_reg_to_local_stack_frame_p (regno, offset)
+ || (lea_rsp_pattern_p (offset) && offset < 0))
{
m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
continue;
@@ -1300,9 +1358,10 @@ UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& t
// If there is no description of the prologue, don't try to augment this eh_frame
// unwinder code, fall back to assembly parsing instead.
- if (first_row->GetCFAType() != UnwindPlan::Row::CFAType::CFAIsRegisterPlusOffset
- || RegisterNumber (thread, unwind_plan.GetRegisterKind(), first_row->GetCFARegister()) != sp_regnum
- || first_row->GetCFAOffset() != wordsize)
+ if (first_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::isRegisterPlusOffset
+ || RegisterNumber (thread, unwind_plan.GetRegisterKind(),
+ first_row->GetCFAValue().GetRegisterNumber()) != sp_regnum
+ || first_row->GetCFAValue().GetOffset() != wordsize)
{
return false;
}
@@ -1326,9 +1385,9 @@ UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& t
// We're checking that both of them have an unwind rule like "CFA=esp+4" or CFA+rsp+8".
- if (first_row->GetCFAType() == last_row->GetCFAType()
- && first_row->GetCFARegister() == last_row->GetCFARegister()
- && first_row->GetCFAOffset() == last_row->GetCFAOffset())
+ if (first_row->GetCFAValue().GetValueType() == last_row->GetCFAValue().GetValueType()
+ && first_row->GetCFAValue().GetRegisterNumber() == last_row->GetCFAValue().GetRegisterNumber()
+ && first_row->GetCFAValue().GetOffset() == last_row->GetCFAValue().GetOffset())
{
// Get the register locations for eip/rip from the first & last rows.
// Are they both CFA plus an offset? Is it the same offset?
diff --git a/source/Symbol/Block.cpp b/source/Symbol/Block.cpp
index 6a5c651cd017..94fa166bb265 100644
--- a/source/Symbol/Block.cpp
+++ b/source/Symbol/Block.cpp
@@ -9,8 +9,6 @@
#include "lldb/Symbol/Block.h"
-#include "lldb/lldb-private-log.h"
-
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
diff --git a/source/Symbol/ClangASTContext.cpp b/source/Symbol/ClangASTContext.cpp
index da25eb84f19e..3c3e2e51d9af 100644
--- a/source/Symbol/ClangASTContext.cpp
+++ b/source/Symbol/ClangASTContext.cpp
@@ -109,13 +109,8 @@ ClangASTContext::ConvertAccessTypeToAccessSpecifier (AccessType access)
return AS_none;
}
-
static void
-ParseLangArgs
-(
- LangOptions &Opts,
- InputKind IK
-)
+ParseLangArgs (LangOptions &Opts, InputKind IK, const char* triple)
{
// FIXME: Cleanup per-file based stuff.
@@ -144,6 +139,7 @@ ParseLangArgs
LangStd = LangStandard::lang_opencl;
break;
case IK_CUDA:
+ case IK_PreprocessedCuda:
LangStd = LangStandard::lang_cuda;
break;
case IK_Asm:
@@ -234,7 +230,7 @@ ParseLangArgs
// Opts.Exceptions = Args.hasArg(OPT_fexceptions);
// Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
// Opts.Blocks = Args.hasArg(OPT_fblocks);
-// Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
+ Opts.CharIsSigned = ArchSpec(triple).CharIsSignedByDefault();
// Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
// Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
// Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
@@ -405,7 +401,14 @@ ClangASTContext::getASTContext()
*getIdentifierTable(),
*getSelectorTable(),
*getBuiltinContext()));
- m_ast_ap->InitBuiltinTypes(*getTargetInfo());
+
+ m_ast_ap->getDiagnostics().setClient(getDiagnosticConsumer(), false);
+
+ // This can be NULL if we don't know anything about the architecture or if the
+ // target for an architecture isn't enabled in the llvm/clang that we built
+ TargetInfo *target_info = getTargetInfo();
+ if (target_info)
+ m_ast_ap->InitBuiltinTypes(*target_info);
if ((m_callback_tag_decl || m_callback_objc_decl) && m_callback_baton)
{
@@ -413,8 +416,6 @@ ClangASTContext::getASTContext()
//m_ast_ap->getTranslationUnitDecl()->setHasExternalVisibleStorage();
}
- m_ast_ap->getDiagnostics().setClient(getDiagnosticConsumer(), false);
-
GetASTMap().Insert(m_ast_ap.get(), this);
}
return m_ast_ap.get();
@@ -449,7 +450,7 @@ ClangASTContext::getLanguageOptions()
if (m_language_options_ap.get() == nullptr)
{
m_language_options_ap.reset(new LangOptions());
- ParseLangArgs(*m_language_options_ap, IK_ObjCXX);
+ ParseLangArgs(*m_language_options_ap, IK_ObjCXX, GetTargetTriple());
// InitializeLangOptions(*m_language_options_ap, IK_ObjCXX);
}
return m_language_options_ap.get();
@@ -908,7 +909,8 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name
if (type_name)
{
if (streq(type_name, "wchar_t") &&
- QualTypeMatchesBitSize (bit_size, ast, ast->WCharTy))
+ QualTypeMatchesBitSize (bit_size, ast, ast->WCharTy) &&
+ (getTargetInfo() && TargetInfo::isTypeSigned (getTargetInfo()->getWCharType())))
return ClangASTType (ast, ast->WCharTy.getAsOpaquePtr());
if (streq(type_name, "void") &&
QualTypeMatchesBitSize (bit_size, ast, ast->VoidTy))
@@ -951,18 +953,13 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name
if (QualTypeMatchesBitSize (bit_size, ast, ast->Int128Ty))
return ClangASTType (ast, ast->Int128Ty.getAsOpaquePtr());
break;
-
+
case DW_ATE_signed_char:
- if (type_name)
+ if (ast->getLangOpts().CharIsSigned && type_name && streq(type_name, "char"))
{
- if (streq(type_name, "signed char"))
- {
- if (QualTypeMatchesBitSize (bit_size, ast, ast->SignedCharTy))
- return ClangASTType (ast, ast->SignedCharTy.getAsOpaquePtr());
- }
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy))
+ return ClangASTType (ast, ast->CharTy.getAsOpaquePtr());
}
- if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy))
- return ClangASTType (ast, ast->CharTy.getAsOpaquePtr());
if (QualTypeMatchesBitSize (bit_size, ast, ast->SignedCharTy))
return ClangASTType (ast, ast->SignedCharTy.getAsOpaquePtr());
break;
@@ -970,6 +967,14 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name
case DW_ATE_unsigned:
if (type_name)
{
+ if (streq(type_name, "wchar_t"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->WCharTy))
+ {
+ if (!(getTargetInfo() && TargetInfo::isTypeSigned (getTargetInfo()->getWCharType())))
+ return ClangASTType (ast, ast->WCharTy.getAsOpaquePtr());
+ }
+ }
if (strstr(type_name, "long long"))
{
if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongLongTy))
@@ -1012,8 +1017,13 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name
if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedInt128Ty))
return ClangASTType (ast, ast->UnsignedInt128Ty.getAsOpaquePtr());
break;
-
+
case DW_ATE_unsigned_char:
+ if (!ast->getLangOpts().CharIsSigned && type_name && streq(type_name, "char"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy))
+ return ClangASTType (ast, ast->CharTy.getAsOpaquePtr());
+ }
if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy))
return ClangASTType (ast, ast->UnsignedCharTy.getAsOpaquePtr());
if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy))
diff --git a/source/Symbol/ClangASTImporter.cpp b/source/Symbol/ClangASTImporter.cpp
index a925f808f858..64a7323d25cf 100644
--- a/source/Symbol/ClangASTImporter.cpp
+++ b/source/Symbol/ClangASTImporter.cpp
@@ -274,7 +274,10 @@ ClangASTImporter::CompleteObjCInterfaceDecl (clang::ObjCInterfaceDecl *interface
if (minion_sp)
minion_sp->ImportDefinitionTo(interface_decl, decl_origin.decl);
-
+
+ if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass())
+ RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0));
+
return true;
}
@@ -286,7 +289,12 @@ ClangASTImporter::RequireCompleteType (clang::QualType type)
if (const TagType *tag_type = type->getAs<TagType>())
{
- return CompleteTagDecl(tag_type->getDecl());
+ TagDecl *tag_decl = tag_type->getDecl();
+
+ if (tag_decl->getDefinition() || tag_decl->isBeingDefined())
+ return true;
+
+ return CompleteTagDecl(tag_decl);
}
if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>())
{
diff --git a/source/Symbol/ClangASTType.cpp b/source/Symbol/ClangASTType.cpp
index eaff90ab8a0a..a62cc9f45a6b 100644
--- a/source/Symbol/ClangASTType.cpp
+++ b/source/Symbol/ClangASTType.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Symbol/ClangASTType.h"
#include "clang/AST/ASTConsumer.h"
@@ -30,6 +28,8 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Signals.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/raw_ostream.h"
@@ -43,8 +43,10 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/VerifyDecl.h"
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
#include <iterator>
@@ -313,6 +315,18 @@ ClangASTType::IsVectorType (ClangASTType *element_type,
return true;
}
break;
+ case clang::Type::ExtVector:
+ {
+ const clang::ExtVectorType *ext_vector_type = qual_type->getAs<clang::ExtVectorType>();
+ if (ext_vector_type)
+ {
+ if (size)
+ *size = ext_vector_type->getNumElements();
+ if (element_type)
+ *element_type = ClangASTType(m_ast, ext_vector_type->getElementType().getAsOpaquePtr());
+ }
+ return true;
+ }
default:
break;
}
@@ -493,7 +507,7 @@ ClangASTType::IsHomogeneousAggregate (ClangASTType* base_type_ptr) const
}
else if (field_qual_type->isVectorType() || field_qual_type->isExtVectorType())
{
- const clang::VectorType *array = llvm::cast<clang::VectorType>(field_qual_type.getTypePtr());
+ const clang::VectorType *array = field_qual_type.getTypePtr()->getAs<clang::VectorType>();
if (array && array->getNumElements() <= 4)
{
if (num_fields == 0)
@@ -2093,7 +2107,7 @@ ClangASTType::GetBasicTypeFromAST (lldb::BasicType basic_type) const
//----------------------------------------------------------------------
uint64_t
-ClangASTType::GetBitSize (ExecutionContext *exe_ctx) const
+ClangASTType::GetBitSize (ExecutionContextScope *exe_scope) const
{
if (GetCompleteType ())
{
@@ -2102,9 +2116,12 @@ ClangASTType::GetBitSize (ExecutionContext *exe_ctx) const
{
case clang::Type::ObjCInterface:
case clang::Type::ObjCObject:
- if (exe_ctx && exe_ctx->GetProcessPtr())
+ {
+ ExecutionContext exe_ctx (exe_scope);
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
{
- ObjCLanguageRuntime *objc_runtime = exe_ctx->GetProcessPtr()->GetObjCLanguageRuntime();
+ ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime();
if (objc_runtime)
{
uint64_t bit_size = 0;
@@ -2118,14 +2135,18 @@ ClangASTType::GetBitSize (ExecutionContext *exe_ctx) const
if (!g_printed)
{
StreamString s;
- s.Printf("warning: trying to determine the size of type ");
DumpTypeDescription(&s);
- s.Printf("\n without a valid ExecutionContext. this is not reliable. please file a bug against LLDB.\nbacktrace:\n");
- Host::Backtrace(s, 10);
- printf("%s\n", s.GetData());
+
+ llvm::outs() << "warning: trying to determine the size of type ";
+ llvm::outs() << s.GetString() << "\n";
+ llvm::outs() << "without a valid ExecutionContext. this is not reliable. please file a bug against LLDB.\n";
+ llvm::outs() << "backtrace:\n";
+ llvm::sys::PrintStackTrace(llvm::outs());
+ llvm::outs() << "\n";
g_printed = true;
}
}
+ }
// fallthrough
default:
const uint32_t bit_size = m_ast->getTypeSize (qual_type);
@@ -2143,11 +2164,12 @@ ClangASTType::GetBitSize (ExecutionContext *exe_ctx) const
}
uint64_t
-ClangASTType::GetByteSize (ExecutionContext *exe_ctx) const
+ClangASTType::GetByteSize (ExecutionContextScope *exe_scope) const
{
- return (GetBitSize (exe_ctx) + 7) / 8;
+ return (GetBitSize (exe_scope) + 7) / 8;
}
+
size_t
ClangASTType::GetTypeBitAlign () const
{
@@ -2224,6 +2246,24 @@ ClangASTType::GetEncoding (uint64_t &count) const
case clang::BuiltinType::ObjCSel: return lldb::eEncodingUint;
case clang::BuiltinType::NullPtr: return lldb::eEncodingUint;
+
+ case clang::BuiltinType::Kind::ARCUnbridgedCast:
+ case clang::BuiltinType::Kind::BoundMember:
+ case clang::BuiltinType::Kind::BuiltinFn:
+ case clang::BuiltinType::Kind::Dependent:
+ case clang::BuiltinType::Kind::Half:
+ case clang::BuiltinType::Kind::OCLEvent:
+ case clang::BuiltinType::Kind::OCLImage1d:
+ case clang::BuiltinType::Kind::OCLImage1dArray:
+ case clang::BuiltinType::Kind::OCLImage1dBuffer:
+ case clang::BuiltinType::Kind::OCLImage2d:
+ case clang::BuiltinType::Kind::OCLImage2dArray:
+ case clang::BuiltinType::Kind::OCLImage3d:
+ case clang::BuiltinType::Kind::OCLSampler:
+ case clang::BuiltinType::Kind::Overload:
+ case clang::BuiltinType::Kind::PseudoObject:
+ case clang::BuiltinType::Kind::UnknownAny:
+ break;
}
break;
// All pointer types are represented as unsigned integer encodings.
@@ -3478,7 +3518,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
child_byte_offset = bit_offset/8;
ClangASTType base_class_clang_type(m_ast, base_class->getType());
child_name = base_class_clang_type.GetTypeName().AsCString("");
- uint64_t base_class_clang_type_bit_size = base_class_clang_type.GetBitSize(nullptr);
+ uint64_t base_class_clang_type_bit_size = base_class_clang_type.GetBitSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
// Base classes bit sizes should be a multiple of 8 bits in size
assert (base_class_clang_type_bit_size % 8 == 0);
@@ -3506,7 +3546,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
// alignment (field_type_info.second) from the AST context.
ClangASTType field_clang_type (m_ast, field->getType());
assert(field_idx < record_layout.getFieldCount());
- child_byte_size = field_clang_type.GetByteSize(exe_ctx);
+ child_byte_size = field_clang_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
// Figure out the field offset within the current struct/union/class type
bit_offset = record_layout.getFieldOffset (field_idx);
@@ -3671,7 +3711,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
// We have a pointer to an simple type
if (idx == 0 && pointee_clang_type.GetCompleteType())
{
- child_byte_size = pointee_clang_type.GetByteSize(exe_ctx);
+ child_byte_size = pointee_clang_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
child_byte_offset = 0;
return pointee_clang_type;
}
@@ -3690,9 +3730,9 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
if (element_type.GetCompleteType())
{
char element_name[64];
- ::snprintf (element_name, sizeof (element_name), "[%zu]", idx);
+ ::snprintf(element_name, sizeof(element_name), "[%" PRIu64 "]", static_cast<uint64_t>(idx));
child_name.assign(element_name);
- child_byte_size = element_type.GetByteSize(exe_ctx);
+ child_byte_size = element_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
child_byte_offset = (int32_t)idx * (int32_t)child_byte_size;
return element_type;
}
@@ -3711,9 +3751,9 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
if (element_type.GetCompleteType())
{
char element_name[64];
- ::snprintf (element_name, sizeof (element_name), "[%zu]", idx);
+ ::snprintf(element_name, sizeof(element_name), "[%" PRIu64 "]", static_cast<uint64_t>(idx));
child_name.assign(element_name);
- child_byte_size = element_type.GetByteSize(exe_ctx);
+ child_byte_size = element_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
child_byte_offset = (int32_t)idx * (int32_t)child_byte_size;
return element_type;
}
@@ -3763,7 +3803,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
// We have a pointer to an simple type
if (idx == 0)
{
- child_byte_size = pointee_clang_type.GetByteSize(exe_ctx);
+ child_byte_size = pointee_clang_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
child_byte_offset = 0;
return pointee_clang_type;
}
@@ -3807,7 +3847,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
// We have a pointer to an simple type
if (idx == 0)
{
- child_byte_size = pointee_clang_type.GetByteSize(exe_ctx);
+ child_byte_size = pointee_clang_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
child_byte_offset = 0;
return pointee_clang_type;
}
@@ -5136,7 +5176,7 @@ ClangASTType::AddMethodToCXXRecordType (const char *name,
{
// Check the number of operator parameters. Sometimes we have
// seen bad DWARF that doesn't correctly describe operators and
- // if we try to create a methed and add it to the class, clang
+ // if we try to create a method and add it to the class, clang
// will assert and crash, so we need to make sure things are
// acceptable.
if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount (op_kind, num_params))
@@ -5358,6 +5398,7 @@ ClangASTType::AddObjCClassProperty (const char *property_name,
&m_ast->Idents.get(property_name),
clang::SourceLocation(), //Source Location for AT
clang::SourceLocation(), //Source location for (
+ ivar_decl ? ivar_decl->getType() : property_clang_type.GetQualType(),
prop_type_source);
if (property_decl)
@@ -6123,7 +6164,7 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
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
- // first member) or comman (for member 2 and beyong) for
+ // first member) or comma (for member 2 and beyond) for
// the struct/union/class member.
if (child_idx == 0)
s->PutChar('{');
@@ -6238,7 +6279,7 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
for (element_idx = 0; element_idx < element_count; ++element_idx)
{
// Print the starting squiggly bracket (if this is the
- // first member) or comman (for member 2 and beyong) for
+ // first member) or comma (for member 2 and beyond) for
// the struct/union/class member.
if (element_idx == 0)
s->PutChar('{');
@@ -6345,7 +6386,7 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
break;
default:
- // We are down the a scalar type that we just need to display.
+ // We are down to a scalar type that we just need to display.
data.Dump(s,
data_byte_offset,
format,
@@ -6454,7 +6495,7 @@ ClangASTType::DumpTypeValue (Stream *s,
// format was not enum, just fall through and dump the value as requested....
default:
- // We are down the a scalar type that we just need to display.
+ // We are down to a scalar type that we just need to display.
{
uint32_t item_count = 1;
// A few formats, we might need to modify our size and count for depending
@@ -6913,7 +6954,7 @@ ClangASTType::ReadFromMemory (lldb_private::ExecutionContext *exe_ctx,
if (!GetCompleteType())
return false;
- const uint64_t byte_size = GetByteSize(exe_ctx);
+ const uint64_t byte_size = GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
if (data.GetByteSize() < byte_size)
{
lldb::DataBufferSP data_sp(new DataBufferHeap (byte_size, '\0'));
@@ -6963,7 +7004,7 @@ ClangASTType::WriteToMemory (lldb_private::ExecutionContext *exe_ctx,
if (!GetCompleteType())
return false;
- const uint64_t byte_size = GetByteSize(exe_ctx);
+ const uint64_t byte_size = GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
if (byte_size > 0)
{
diff --git a/source/Symbol/ClangExternalASTSourceCallbacks.cpp b/source/Symbol/ClangExternalASTSourceCallbacks.cpp
index bdc32654cc10..cd6972cce972 100644
--- a/source/Symbol/ClangExternalASTSourceCallbacks.cpp
+++ b/source/Symbol/ClangExternalASTSourceCallbacks.cpp
@@ -141,13 +141,12 @@ ClangExternalASTSourceCallbacks::CompleteType (ObjCInterfaceDecl *objc_decl)
m_callback_objc_decl (m_callback_baton, objc_decl);
}
-bool
-ClangExternalASTSourceCallbacks::layoutRecordType(const clang::RecordDecl *Record,
- uint64_t &Size,
- uint64_t &Alignment,
- llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
- llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets)
+bool
+ClangExternalASTSourceCallbacks::layoutRecordType(
+ const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets)
{
if (m_callback_layout_record_type)
return m_callback_layout_record_type(m_callback_baton,
diff --git a/source/Symbol/CompactUnwindInfo.cpp b/source/Symbol/CompactUnwindInfo.cpp
index e7153446cd16..afef4e480e8e 100644
--- a/source/Symbol/CompactUnwindInfo.cpp
+++ b/source/Symbol/CompactUnwindInfo.cpp
@@ -13,6 +13,7 @@
#include <algorithm>
#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
@@ -34,13 +35,15 @@ namespace lldb_private {
// Constants from <mach-o/compact_unwind_encoding.h>
- enum {
+ FLAGS_ANONYMOUS_ENUM()
+ {
UNWIND_IS_NOT_FUNCTION_START = 0x80000000,
UNWIND_HAS_LSDA = 0x40000000,
UNWIND_PERSONALITY_MASK = 0x30000000,
};
- enum {
+ FLAGS_ANONYMOUS_ENUM()
+ {
UNWIND_X86_MODE_MASK = 0x0F000000,
UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
@@ -58,7 +61,8 @@ namespace lldb_private {
UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
};
- enum {
+ enum
+ {
UNWIND_X86_REG_NONE = 0,
UNWIND_X86_REG_EBX = 1,
UNWIND_X86_REG_ECX = 2,
@@ -67,7 +71,9 @@ namespace lldb_private {
UNWIND_X86_REG_ESI = 5,
UNWIND_X86_REG_EBP = 6,
};
- enum {
+
+ FLAGS_ANONYMOUS_ENUM()
+ {
UNWIND_X86_64_MODE_MASK = 0x0F000000,
UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
@@ -85,7 +91,8 @@ namespace lldb_private {
UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
};
- enum {
+ enum
+ {
UNWIND_X86_64_REG_NONE = 0,
UNWIND_X86_64_REG_RBX = 1,
UNWIND_X86_64_REG_R12 = 2,
@@ -94,7 +101,7 @@ namespace lldb_private {
UNWIND_X86_64_REG_R15 = 5,
UNWIND_X86_64_REG_RBP = 6,
};
-};
+}
#ifndef UNWIND_SECOND_LEVEL_REGULAR
@@ -115,7 +122,7 @@ namespace lldb_private {
#define EXTRACT_BITS(value, mask) \
( (value >> llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \
- (((1 << llvm::CountPopulation_32(static_cast<uint32_t>(mask))))-1) )
+ (((1 << llvm::countPopulation(static_cast<uint32_t>(mask))))-1) )
@@ -282,9 +289,17 @@ CompactUnwindInfo::ScanIndex (const ProcessSP &process_sp)
uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
- if (m_unwind_header.version != 1)
+ if (m_unwind_header.common_encodings_array_offset > m_unwindinfo_data.GetByteSize()
+ || m_unwind_header.personality_array_offset > m_unwindinfo_data.GetByteSize()
+ || indexSectionOffset > m_unwindinfo_data.GetByteSize()
+ || offset > m_unwindinfo_data.GetByteSize())
{
+ Host::SystemLog (Host::eSystemLogError,
+ "error: Invalid offset encountered in compact unwind info, skipping\n");
+ // don't trust anything from this compact_unwind section if it looks
+ // blatently invalid data in the header.
m_indexes_computed = eLazyBoolNo;
+ return;
}
// Parse the basic information from the indexes
@@ -510,7 +525,7 @@ CompactUnwindInfo::GetCompactUnwindInfoForFunction (Target &target, Address addr
}
auto next_it = it + 1;
- if (next_it != m_indexes.begin())
+ if (next_it != m_indexes.end())
{
// initialize the function offset end range to be the start of the
// next index offset. If we find an entry which is at the end of
@@ -720,8 +735,9 @@ CompactUnwindInfo::CreateUnwindPlan_x86_64 (Target &target, FunctionInfo &functi
{
case UNWIND_X86_64_MODE_RBP_FRAME:
{
- row->SetCFARegister (translate_to_eh_frame_regnum_x86_64 (UNWIND_X86_64_REG_RBP));
- row->SetCFAOffset (2 * wordsize);
+ row->GetCFAValue().SetIsRegisterPlusOffset (
+ translate_to_eh_frame_regnum_x86_64 (UNWIND_X86_64_REG_RBP),
+ 2 * wordsize);
row->SetOffset (0);
row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rbp, wordsize * -2, true);
row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true);
@@ -759,7 +775,8 @@ CompactUnwindInfo::CreateUnwindPlan_x86_64 (Target &target, FunctionInfo &functi
case UNWIND_X86_64_MODE_STACK_IND:
{
// The clang in Xcode 6 is emitting incorrect compact unwind encodings for this
- // style of unwind. It was fixed in llvm r217020.
+ // style of unwind. It was fixed in llvm r217020.
+ // The clang in Xcode 7 has this fixed.
return false;
}
break;
@@ -809,16 +826,9 @@ CompactUnwindInfo::CreateUnwindPlan_x86_64 (Target &target, FunctionInfo &functi
}
}
- if (mode == UNWIND_X86_64_MODE_STACK_IND)
- {
- row->SetCFAOffset (stack_size);
- }
- else
- {
- row->SetCFAOffset (stack_size * wordsize);
- }
+ int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND ? stack_size : stack_size * wordsize;
+ row->GetCFAValue().SetIsRegisterPlusOffset (x86_64_eh_regnum::rsp, offset);
- row->SetCFARegister (x86_64_eh_regnum::rsp);
row->SetOffset (0);
row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true);
row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true);
@@ -832,7 +842,7 @@ CompactUnwindInfo::CreateUnwindPlan_x86_64 (Target &target, FunctionInfo &functi
//
// This is done with Lehmer code permutation, e.g. see
// http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
- int permunreg[6];
+ int permunreg[6] = {0, 0, 0, 0, 0, 0};
// This decodes the variable-base number in the 10 bits
// and gives us the Lehmer code sequence which can then
@@ -892,7 +902,7 @@ CompactUnwindInfo::CreateUnwindPlan_x86_64 (Target &target, FunctionInfo &functi
// Decode the Lehmer code for this permutation of
// the registers v. http://en.wikipedia.org/wiki/Lehmer_code
- int registers[6];
+ int registers[6] = { UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE };
bool used[7] = { false, false, false, false, false, false, false };
for (uint32_t i = 0; i < register_count; i++)
{
@@ -1009,8 +1019,8 @@ CompactUnwindInfo::CreateUnwindPlan_i386 (Target &target, FunctionInfo &function
{
case UNWIND_X86_MODE_EBP_FRAME:
{
- row->SetCFARegister (translate_to_eh_frame_regnum_i386 (UNWIND_X86_REG_EBP));
- row->SetCFAOffset (2 * wordsize);
+ row->GetCFAValue().SetIsRegisterPlusOffset (
+ translate_to_eh_frame_regnum_i386 (UNWIND_X86_REG_EBP), 2 * wordsize);
row->SetOffset (0);
row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::ebp, wordsize * -2, true);
row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true);
@@ -1091,17 +1101,8 @@ CompactUnwindInfo::CreateUnwindPlan_i386 (Target &target, FunctionInfo &function
}
}
- row->SetCFARegister (i386_eh_regnum::esp);
-
- if (mode == UNWIND_X86_MODE_STACK_IND)
- {
- row->SetCFAOffset (stack_size);
- }
- else
- {
- row->SetCFAOffset (stack_size * wordsize);
- }
-
+ int32_t offset = mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
+ row->GetCFAValue().SetIsRegisterPlusOffset (i386_eh_regnum::esp, offset);
row->SetOffset (0);
row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true);
row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true);
@@ -1115,7 +1116,7 @@ CompactUnwindInfo::CreateUnwindPlan_i386 (Target &target, FunctionInfo &function
//
// This is done with Lehmer code permutation, e.g. see
// http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
- int permunreg[6];
+ int permunreg[6] = {0, 0, 0, 0, 0, 0};
// This decodes the variable-base number in the 10 bits
// and gives us the Lehmer code sequence which can then
@@ -1175,7 +1176,7 @@ CompactUnwindInfo::CreateUnwindPlan_i386 (Target &target, FunctionInfo &function
// Decode the Lehmer code for this permutation of
// the registers v. http://en.wikipedia.org/wiki/Lehmer_code
- int registers[6];
+ int registers[6] = { UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE };
bool used[7] = { false, false, false, false, false, false, false };
for (uint32_t i = 0; i < register_count; i++)
{
diff --git a/source/Symbol/CompileUnit.cpp b/source/Symbol/CompileUnit.cpp
index 6483258ee678..d43ef44a1376 100644
--- a/source/Symbol/CompileUnit.cpp
+++ b/source/Symbol/CompileUnit.cpp
@@ -149,9 +149,9 @@ CompileUnit::GetFunctionAtIndex (size_t idx)
}
//----------------------------------------------------------------------
-// Find functions using the a Mangled::Tokens token list. This
-// function currently implements an interative approach designed to find
-// all instances of certain functions. It isn't designed to the the
+// Find functions using the Mangled::Tokens token list. This
+// function currently implements an interactive approach designed to find
+// all instances of certain functions. It isn't designed to the
// quickest way to lookup functions as it will need to iterate through
// all functions and see if they match, though it does provide a powerful
// and context sensitive way to search for all functions with a certain
@@ -292,7 +292,7 @@ CompileUnit::FindLineEntry (uint32_t start_idx, uint32_t line, const FileSpec* f
else
{
// All the line table entries actually point to the version of the Compile
- // Unit that is in the support files (the one at 0 was artifically added.)
+ // Unit that is in the support files (the one at 0 was artificially added.)
// So prefer the one further on in the support files if it exists...
FileSpecList &support_files = GetSupportFiles();
const bool full = true;
@@ -436,6 +436,23 @@ CompileUnit::SetVariableList(VariableListSP &variables)
m_variables = variables;
}
+const std::vector<ConstString> &
+CompileUnit::GetImportedModules ()
+{
+ if (m_imported_modules.empty() &&
+ m_flags.IsClear(flagsParsedImportedModules))
+ {
+ m_flags.Set(flagsParsedImportedModules);
+ if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor())
+ {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ symbol_vendor->ParseImportedModules(sc, m_imported_modules);
+ }
+ }
+ return m_imported_modules;
+}
+
FileSpecList&
CompileUnit::GetSupportFiles ()
{
diff --git a/source/Symbol/DWARFCallFrameInfo.cpp b/source/Symbol/DWARFCallFrameInfo.cpp
index 78d262307c24..a5f9017918dd 100644
--- a/source/Symbol/DWARFCallFrameInfo.cpp
+++ b/source/Symbol/DWARFCallFrameInfo.cpp
@@ -197,7 +197,7 @@ DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset)
const size_t aug_str_len = strlen(cie_sp->augmentation);
// A 'z' may be present as the first character of the string.
// If present, the Augmentation Data field shall be present.
- // The contents of the Augmentation Data shall be intepreted
+ // The contents of the Augmentation Data shall be interpreted
// according to other characters in the Augmentation String.
if (cie_sp->augmentation[0] == 'z')
{
@@ -276,38 +276,8 @@ DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset)
uint8_t primary_opcode = inst & 0xC0;
uint8_t extended_opcode = inst & 0x3F;
- if (extended_opcode == DW_CFA_def_cfa)
- {
- // Takes two unsigned LEB128 operands representing a register
- // number and a (non-factored) offset. The required action
- // is to define the current CFA rule to use the provided
- // register and offset.
- uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- int op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);
- cie_sp->initial_row.SetCFARegister (reg_num);
- cie_sp->initial_row.SetCFAOffset (op_offset);
- continue;
- }
- if (primary_opcode == DW_CFA_offset)
- {
- // 0x80 - high 2 bits are 0x2, lower 6 bits are register.
- // Takes two arguments: an unsigned LEB128 constant representing a
- // factored offset and a register number. The required action is to
- // change the rule for the register indicated by the register number
- // to be an offset(N) rule with a value of
- // (N = factored offset * data_align).
- uint32_t reg_num = extended_opcode;
- int op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * cie_sp->data_align;
- UnwindPlan::Row::RegisterLocation reg_location;
- reg_location.SetAtCFAPlusOffset(op_offset);
- cie_sp->initial_row.SetRegisterInfo (reg_num, reg_location);
- continue;
- }
- if (extended_opcode == DW_CFA_nop)
- {
- continue;
- }
- break; // Stop if we hit an unrecognized opcode
+ if (!HandleCommonDwarfOpcode(primary_opcode, extended_opcode, cie_sp->data_align, offset, cie_sp->initial_row))
+ break; // Stop if we hit an unrecognized opcode
}
}
@@ -366,6 +336,31 @@ DWARFCallFrameInfo::GetFDEIndex ()
cie_offset = current_entry + 4 - cie_id;
}
+ if (next_entry > m_cfi_data.GetByteSize() + 1)
+ {
+ Host::SystemLog (Host::eSystemLogError,
+ "error: Invalid fde/cie next entry offset of 0x%x found in cie/fde at 0x%x\n",
+ next_entry,
+ current_entry);
+ // Don't trust anything in this eh_frame section if we find blatently
+ // invalid data.
+ m_fde_index.Clear();
+ m_fde_index_initialized = true;
+ return;
+ }
+ if (cie_offset > m_cfi_data.GetByteSize())
+ {
+ Host::SystemLog (Host::eSystemLogError,
+ "error: Invalid cie offset of 0x%x found in cie/fde at 0x%x\n",
+ cie_offset,
+ current_entry);
+ // Don't trust anything in this eh_frame section if we find blatently
+ // invalid data.
+ m_fde_index.Clear();
+ m_fde_index_initialized = true;
+ return;
+ }
+
if (cie_id == 0 || cie_id == UINT32_MAX || len == 0)
{
m_cie_map[current_entry] = ParseCIE (current_entry);
@@ -490,8 +485,6 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
unwind_plan.SetPersonalityFunctionPtr (personality_function_ptr);
}
- uint32_t reg_num = 0;
- int32_t op_offset = 0;
uint32_t code_align = cie->code_align;
int32_t data_align = cie->data_align;
@@ -512,11 +505,13 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
uint8_t primary_opcode = inst & 0xC0;
uint8_t extended_opcode = inst & 0x3F;
- if (primary_opcode)
+ if (!HandleCommonDwarfOpcode(primary_opcode, extended_opcode, data_align, offset, *row))
{
- switch (primary_opcode)
+ if (primary_opcode)
{
- case DW_CFA_advance_loc : // (Row Creation Instruction)
+ switch (primary_opcode)
+ {
+ case DW_CFA_advance_loc : // (Row Creation Instruction)
{ // 0x40 - high 2 bits are 0x1, lower 6 bits are delta
// takes a single argument that represents a constant delta. The
// required action is to create a new table row with a location
@@ -528,29 +523,15 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
*newrow = *row.get();
row.reset (newrow);
row->SlideOffset(extended_opcode * code_align);
+ break;
}
- break;
-
- case DW_CFA_offset :
- { // 0x80 - high 2 bits are 0x2, lower 6 bits are register
- // takes two arguments: an unsigned LEB128 constant representing a
- // factored offset and a register number. The required action is to
- // change the rule for the register indicated by the register number
- // to be an offset(N) rule with a value of
- // (N = factored offset * data_align).
- reg_num = extended_opcode;
- op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;
- reg_location.SetAtCFAPlusOffset(op_offset);
- row->SetRegisterInfo (reg_num, reg_location);
- }
- break;
- case DW_CFA_restore :
+ case DW_CFA_restore :
{ // 0xC0 - high 2 bits are 0x3, lower 6 bits are register
// takes a single argument that represents a register number. The
// required action is to change the rule for the indicated register
// to the rule assigned it by the initial_instructions in the CIE.
- reg_num = extended_opcode;
+ uint32_t reg_num = extended_opcode;
// We only keep enough register locations around to
// unwind what is in our thread, and these are organized
// by the register index in that state, so we need to convert our
@@ -558,18 +539,15 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num, reg_location))
row->SetRegisterInfo (reg_num, reg_location);
+ break;
}
- break;
+ }
}
- }
- else
- {
- switch (extended_opcode)
+ else
{
- case DW_CFA_nop : // 0x0
- break;
-
- case DW_CFA_set_loc : // 0x1 (Row Creation Instruction)
+ switch (extended_opcode)
+ {
+ case DW_CFA_set_loc : // 0x1 (Row Creation Instruction)
{
// DW_CFA_set_loc takes a single argument that represents an address.
// The required action is to create a new table row using the
@@ -581,10 +559,10 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
*newrow = *row.get();
row.reset (newrow);
row->SetOffset(m_cfi_data.GetPointer(&offset) - startaddr.GetFileAddress());
+ break;
}
- break;
- case DW_CFA_advance_loc1 : // 0x2 (Row Creation Instruction)
+ case DW_CFA_advance_loc1 : // 0x2 (Row Creation Instruction)
{
// takes a single uword argument that represents a constant delta.
// This instruction is identical to DW_CFA_advance_loc except for the
@@ -594,10 +572,10 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
*newrow = *row.get();
row.reset (newrow);
row->SlideOffset (m_cfi_data.GetU8(&offset) * code_align);
+ break;
}
- break;
- case DW_CFA_advance_loc2 : // 0x3 (Row Creation Instruction)
+ case DW_CFA_advance_loc2 : // 0x3 (Row Creation Instruction)
{
// takes a single uword argument that represents a constant delta.
// This instruction is identical to DW_CFA_advance_loc except for the
@@ -607,10 +585,10 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
*newrow = *row.get();
row.reset (newrow);
row->SlideOffset (m_cfi_data.GetU16(&offset) * code_align);
+ break;
}
- break;
- case DW_CFA_advance_loc4 : // 0x4 (Row Creation Instruction)
+ case DW_CFA_advance_loc4 : // 0x4 (Row Creation Instruction)
{
// takes a single uword argument that represents a constant delta.
// This instruction is identical to DW_CFA_advance_loc except for the
@@ -620,68 +598,21 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
*newrow = *row.get();
row.reset (newrow);
row->SlideOffset (m_cfi_data.GetU32(&offset) * code_align);
+ break;
}
- break;
- case DW_CFA_offset_extended : // 0x5
- {
- // takes two unsigned LEB128 arguments representing a register number
- // and a factored offset. This instruction is identical to DW_CFA_offset
- // except for the encoding and size of the register argument.
- reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;
- reg_location.SetAtCFAPlusOffset(op_offset);
- row->SetRegisterInfo (reg_num, reg_location);
- }
- break;
-
- case DW_CFA_restore_extended : // 0x6
+ case DW_CFA_restore_extended : // 0x6
{
// takes a single unsigned LEB128 argument that represents a register
// number. This instruction is identical to DW_CFA_restore except for
// the encoding and size of the register argument.
- reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num, reg_location))
row->SetRegisterInfo (reg_num, reg_location);
+ break;
}
- break;
- case DW_CFA_undefined : // 0x7
- {
- // takes a single unsigned LEB128 argument that represents a register
- // number. The required action is to set the rule for the specified
- // register to undefined.
- reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- reg_location.SetUndefined();
- row->SetRegisterInfo (reg_num, reg_location);
- }
- break;
-
- case DW_CFA_same_value : // 0x8
- {
- // takes a single unsigned LEB128 argument that represents a register
- // number. The required action is to set the rule for the specified
- // register to same value.
- reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- reg_location.SetSame();
- row->SetRegisterInfo (reg_num, reg_location);
- }
- break;
-
- case DW_CFA_register : // 0x9
- {
- // takes two unsigned LEB128 arguments representing register numbers.
- // The required action is to set the rule for the first register to be
- // the second register.
-
- reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- uint32_t other_reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- reg_location.SetInRegister(other_reg_num);
- row->SetRegisterInfo (reg_num, reg_location);
- }
- break;
-
- case DW_CFA_remember_state : // 0xA
+ case DW_CFA_remember_state : // 0xA
{
// These instructions define a stack of information. Encountering the
// DW_CFA_remember_state instruction means to save the rules for every
@@ -694,184 +625,277 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
UnwindPlan::Row *newrow = new UnwindPlan::Row;
*newrow = *row.get();
row.reset (newrow);
+ break;
}
- break;
-
- case DW_CFA_restore_state : // 0xB
- // These instructions define a stack of information. Encountering the
- // DW_CFA_remember_state instruction means to save the rules for every
- // register on the current row on the stack. Encountering the
- // DW_CFA_restore_state instruction means to pop the set of rules off
- // the stack and place them in the current row. (This operation is
- // useful for compilers that move epilogue code into the body of a
- // function.)
+
+ case DW_CFA_restore_state : // 0xB
{
+ // These instructions define a stack of information. Encountering the
+ // DW_CFA_remember_state instruction means to save the rules for every
+ // register on the current row on the stack. Encountering the
+ // DW_CFA_restore_state instruction means to pop the set of rules off
+ // the stack and place them in the current row. (This operation is
+ // useful for compilers that move epilogue code into the body of a
+ // function.)
+ lldb::addr_t offset = row->GetOffset ();
row = stack.back ();
stack.pop_back ();
+ row->SetOffset (offset);
+ break;
}
- break;
- case DW_CFA_def_cfa : // 0xC (CFA Definition Instruction)
- {
- // Takes two unsigned LEB128 operands representing a register
- // number and a (non-factored) offset. The required action
- // is to define the current CFA rule to use the provided
- // register and offset.
- reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);
- row->SetCFARegister (reg_num);
- row->SetCFAOffset (op_offset);
- }
- break;
+ case DW_CFA_val_offset : // 0x14
+ case DW_CFA_val_offset_sf : // 0x15
+ default:
+ break;
+ }
+ }
+ }
+ }
+ unwind_plan.AppendRow(row);
- case DW_CFA_def_cfa_register : // 0xD (CFA Definition Instruction)
- {
- // takes a single unsigned LEB128 argument representing a register
- // number. The required action is to define the current CFA rule to
- // use the provided register (but to keep the old offset).
- reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- row->SetCFARegister (reg_num);
- }
- break;
+ return true;
+}
- case DW_CFA_def_cfa_offset : // 0xE (CFA Definition Instruction)
- {
- // Takes a single unsigned LEB128 operand representing a
- // (non-factored) offset. The required action is to define
- // the current CFA rule to use the provided offset (but
- // to keep the old register).
- op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);
- row->SetCFAOffset (op_offset);
- }
- break;
+bool
+DWARFCallFrameInfo::HandleCommonDwarfOpcode(uint8_t primary_opcode,
+ uint8_t extended_opcode,
+ int32_t data_align,
+ lldb::offset_t& offset,
+ UnwindPlan::Row& row)
+{
+ UnwindPlan::Row::RegisterLocation reg_location;
- case DW_CFA_def_cfa_expression : // 0xF (CFA Definition Instruction)
- {
- size_t block_len = (size_t)m_cfi_data.GetULEB128(&offset);
- offset += (uint32_t)block_len;
- }
- break;
+ if (primary_opcode)
+ {
+ switch (primary_opcode)
+ {
+ case DW_CFA_offset:
+ { // 0x80 - high 2 bits are 0x2, lower 6 bits are register
+ // takes two arguments: an unsigned LEB128 constant representing a
+ // factored offset and a register number. The required action is to
+ // change the rule for the register indicated by the register number
+ // to be an offset(N) rule with a value of
+ // (N = factored offset * data_align).
+ uint8_t reg_num = extended_opcode;
+ int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;
+ reg_location.SetAtCFAPlusOffset(op_offset);
+ row.SetRegisterInfo(reg_num, reg_location);
+ return true;
+ }
+ }
+ }
+ else
+ {
+ switch (extended_opcode)
+ {
+ case DW_CFA_nop : // 0x0
+ return true;
- case DW_CFA_expression : // 0x10
- {
- // Takes two operands: an unsigned LEB128 value representing
- // a register number, and a DW_FORM_block value representing a DWARF
- // expression. The required action is to change the rule for the
- // register indicated by the register number to be an expression(E)
- // rule where E is the DWARF expression. That is, the DWARF
- // expression computes the address. The value of the CFA is
- // pushed on the DWARF evaluation stack prior to execution of
- // the DWARF expression.
- reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
- const uint8_t *block_data = (uint8_t *)m_cfi_data.GetData(&offset, block_len);
-
- reg_location.SetAtDWARFExpression(block_data, block_len);
- row->SetRegisterInfo (reg_num, reg_location);
- }
- break;
+ case DW_CFA_offset_extended : // 0x5
+ {
+ // takes two unsigned LEB128 arguments representing a register number
+ // and a factored offset. This instruction is identical to DW_CFA_offset
+ // except for the encoding and size of the register argument.
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;
+ UnwindPlan::Row::RegisterLocation reg_location;
+ reg_location.SetAtCFAPlusOffset(op_offset);
+ row.SetRegisterInfo(reg_num, reg_location);
+ return true;
+ }
- case DW_CFA_offset_extended_sf : // 0x11
- {
- // takes two operands: an unsigned LEB128 value representing a
- // register number and a signed LEB128 factored offset. This
- // instruction is identical to DW_CFA_offset_extended except
- //that the second operand is signed and factored.
- reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
- reg_location.SetAtCFAPlusOffset(op_offset);
- row->SetRegisterInfo (reg_num, reg_location);
- }
- break;
+ case DW_CFA_undefined : // 0x7
+ {
+ // takes a single unsigned LEB128 argument that represents a register
+ // number. The required action is to set the rule for the specified
+ // register to undefined.
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ UnwindPlan::Row::RegisterLocation reg_location;
+ reg_location.SetUndefined();
+ row.SetRegisterInfo(reg_num, reg_location);
+ return true;
+ }
- case DW_CFA_def_cfa_sf : // 0x12 (CFA Definition Instruction)
- {
- // Takes two operands: an unsigned LEB128 value representing
- // a register number and a signed LEB128 factored offset.
- // This instruction is identical to DW_CFA_def_cfa except
- // that the second operand is signed and factored.
- reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
- row->SetCFARegister (reg_num);
- row->SetCFAOffset (op_offset);
- }
- break;
+ case DW_CFA_same_value : // 0x8
+ {
+ // takes a single unsigned LEB128 argument that represents a register
+ // number. The required action is to set the rule for the specified
+ // register to same value.
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ UnwindPlan::Row::RegisterLocation reg_location;
+ reg_location.SetSame();
+ row.SetRegisterInfo (reg_num, reg_location);
+ return true;
+ }
- case DW_CFA_def_cfa_offset_sf : // 0x13 (CFA Definition Instruction)
- {
- // takes a signed LEB128 operand representing a factored
- // offset. This instruction is identical to DW_CFA_def_cfa_offset
- // except that the operand is signed and factored.
- op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
- row->SetCFAOffset (op_offset);
- }
- break;
+ case DW_CFA_register : // 0x9
+ {
+ // takes two unsigned LEB128 arguments representing register numbers.
+ // The required action is to set the rule for the first register to be
+ // the second register.
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ uint32_t other_reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ UnwindPlan::Row::RegisterLocation reg_location;
+ reg_location.SetInRegister(other_reg_num);
+ row.SetRegisterInfo (reg_num, reg_location);
+ return true;
+ }
- case DW_CFA_val_expression : // 0x16
- {
- // takes two operands: an unsigned LEB128 value representing a register
- // number, and a DW_FORM_block value representing a DWARF expression.
- // The required action is to change the rule for the register indicated
- // by the register number to be a val_expression(E) rule where E is the
- // DWARF expression. That is, the DWARF expression computes the value of
- // the given register. The value of the CFA is pushed on the DWARF
- // evaluation stack prior to execution of the DWARF expression.
- reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
- const uint8_t* block_data = (uint8_t*)m_cfi_data.GetData(&offset, block_len);
+ case DW_CFA_def_cfa : // 0xC (CFA Definition Instruction)
+ {
+ // Takes two unsigned LEB128 operands representing a register
+ // number and a (non-factored) offset. The required action
+ // is to define the current CFA rule to use the provided
+ // register and offset.
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);
+ row.GetCFAValue().SetIsRegisterPlusOffset (reg_num, op_offset);
+ return true;
+ }
+
+ case DW_CFA_def_cfa_register : // 0xD (CFA Definition Instruction)
+ {
+ // takes a single unsigned LEB128 argument representing a register
+ // number. The required action is to define the current CFA rule to
+ // use the provided register (but to keep the old offset).
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ row.GetCFAValue().SetIsRegisterPlusOffset (reg_num, row.GetCFAValue().GetOffset());
+ return true;
+ }
+
+ case DW_CFA_def_cfa_offset : // 0xE (CFA Definition Instruction)
+ {
+ // Takes a single unsigned LEB128 operand representing a
+ // (non-factored) offset. The required action is to define
+ // the current CFA rule to use the provided offset (but
+ // to keep the old register).
+ int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);
+ row.GetCFAValue().SetIsRegisterPlusOffset(row.GetCFAValue().GetRegisterNumber(), op_offset);
+ return true;
+ }
+
+ case DW_CFA_def_cfa_expression : // 0xF (CFA Definition Instruction)
+ {
+ size_t block_len = (size_t)m_cfi_data.GetULEB128(&offset);
+ const uint8_t *block_data = static_cast<const uint8_t*>(m_cfi_data.GetData(&offset, block_len));
+ row.GetCFAValue().SetIsDWARFExpression(block_data, block_len);
+ return true;
+ }
+
+ case DW_CFA_expression : // 0x10
+ {
+ // Takes two operands: an unsigned LEB128 value representing
+ // a register number, and a DW_FORM_block value representing a DWARF
+ // expression. The required action is to change the rule for the
+ // register indicated by the register number to be an expression(E)
+ // rule where E is the DWARF expression. That is, the DWARF
+ // expression computes the address. The value of the CFA is
+ // pushed on the DWARF evaluation stack prior to execution of
+ // the DWARF expression.
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ const uint8_t *block_data = static_cast<const uint8_t*>(m_cfi_data.GetData(&offset, block_len));
+ UnwindPlan::Row::RegisterLocation reg_location;
+ reg_location.SetAtDWARFExpression(block_data, block_len);
+ row.SetRegisterInfo(reg_num, reg_location);
+ return true;
+ }
+
+ case DW_CFA_offset_extended_sf : // 0x11
+ {
+ // takes two operands: an unsigned LEB128 value representing a
+ // register number and a signed LEB128 factored offset. This
+ // instruction is identical to DW_CFA_offset_extended except
+ //that the second operand is signed and factored.
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
+ UnwindPlan::Row::RegisterLocation reg_location;
+ reg_location.SetAtCFAPlusOffset(op_offset);
+ row.SetRegisterInfo(reg_num, reg_location);
+ return true;
+ }
+
+ case DW_CFA_def_cfa_sf : // 0x12 (CFA Definition Instruction)
+ {
+ // Takes two operands: an unsigned LEB128 value representing
+ // a register number and a signed LEB128 factored offset.
+ // This instruction is identical to DW_CFA_def_cfa except
+ // that the second operand is signed and factored.
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
+ row.GetCFAValue().SetIsRegisterPlusOffset (reg_num, op_offset);
+ return true;
+ }
+
+ case DW_CFA_def_cfa_offset_sf : // 0x13 (CFA Definition Instruction)
+ {
+ // takes a signed LEB128 operand representing a factored
+ // offset. This instruction is identical to DW_CFA_def_cfa_offset
+ // except that the operand is signed and factored.
+ int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
+ uint32_t cfa_regnum = row.GetCFAValue().GetRegisterNumber();
+ row.GetCFAValue().SetIsRegisterPlusOffset(cfa_regnum, op_offset);
+ return true;
+ }
+
+ case DW_CFA_val_expression : // 0x16
+ {
+ // takes two operands: an unsigned LEB128 value representing a register
+ // number, and a DW_FORM_block value representing a DWARF expression.
+ // The required action is to change the rule for the register indicated
+ // by the register number to be a val_expression(E) rule where E is the
+ // DWARF expression. That is, the DWARF expression computes the value of
+ // the given register. The value of the CFA is pushed on the DWARF
+ // evaluation stack prior to execution of the DWARF expression.
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ const uint8_t* block_data = (const uint8_t*)m_cfi_data.GetData(&offset, block_len);
//#if defined(__i386__) || defined(__x86_64__)
-// // The EH frame info for EIP and RIP contains code that looks for traps to
-// // be a specific type and increments the PC.
-// // For i386:
-// // DW_CFA_val_expression where:
-// // eip = DW_OP_breg6(+28), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x34),
-// // DW_OP_deref, DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref,
-// // DW_OP_dup, DW_OP_lit3, DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne,
-// // DW_OP_and, DW_OP_plus
-// // This basically does a:
-// // eip = ucontenxt.mcontext32->gpr.eip;
-// // if (ucontenxt.mcontext32->exc.trapno != 3 && ucontenxt.mcontext32->exc.trapno != 4)
-// // eip++;
-// //
-// // For x86_64:
-// // DW_CFA_val_expression where:
-// // rip = DW_OP_breg3(+48), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x90), DW_OP_deref,
-// // DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref_size(4), DW_OP_dup, DW_OP_lit3,
-// // DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne, DW_OP_and, DW_OP_plus
-// // This basically does a:
-// // rip = ucontenxt.mcontext64->gpr.rip;
-// // if (ucontenxt.mcontext64->exc.trapno != 3 && ucontenxt.mcontext64->exc.trapno != 4)
-// // rip++;
-// // The trap comparisons and increments are not needed as it hoses up the unwound PC which
-// // is expected to point at least past the instruction that causes the fault/trap. So we
-// // take it out by trimming the expression right at the first "DW_OP_swap" opcodes
-// if (block_data != NULL && thread->GetPCRegNum(Thread::GCC) == reg_num)
-// {
-// if (thread->Is64Bit())
-// {
-// if (block_len > 9 && block_data[8] == DW_OP_swap && block_data[9] == DW_OP_plus_uconst)
-// block_len = 8;
-// }
-// else
-// {
-// if (block_len > 8 && block_data[7] == DW_OP_swap && block_data[8] == DW_OP_plus_uconst)
-// block_len = 7;
-// }
-// }
+// // The EH frame info for EIP and RIP contains code that looks for traps to
+// // be a specific type and increments the PC.
+// // For i386:
+// // DW_CFA_val_expression where:
+// // eip = DW_OP_breg6(+28), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x34),
+// // DW_OP_deref, DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref,
+// // DW_OP_dup, DW_OP_lit3, DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne,
+// // DW_OP_and, DW_OP_plus
+// // This basically does a:
+// // eip = ucontenxt.mcontext32->gpr.eip;
+// // if (ucontenxt.mcontext32->exc.trapno != 3 && ucontenxt.mcontext32->exc.trapno != 4)
+// // eip++;
+// //
+// // For x86_64:
+// // DW_CFA_val_expression where:
+// // rip = DW_OP_breg3(+48), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x90), DW_OP_deref,
+// // DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref_size(4), DW_OP_dup, DW_OP_lit3,
+// // DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne, DW_OP_and, DW_OP_plus
+// // This basically does a:
+// // rip = ucontenxt.mcontext64->gpr.rip;
+// // if (ucontenxt.mcontext64->exc.trapno != 3 && ucontenxt.mcontext64->exc.trapno != 4)
+// // rip++;
+// // The trap comparisons and increments are not needed as it hoses up the unwound PC which
+// // is expected to point at least past the instruction that causes the fault/trap. So we
+// // take it out by trimming the expression right at the first "DW_OP_swap" opcodes
+// if (block_data != NULL && thread->GetPCRegNum(Thread::GCC) == reg_num)
+// {
+// if (thread->Is64Bit())
+// {
+// if (block_len > 9 && block_data[8] == DW_OP_swap && block_data[9] == DW_OP_plus_uconst)
+// block_len = 8;
+// }
+// else
+// {
+// if (block_len > 8 && block_data[7] == DW_OP_swap && block_data[8] == DW_OP_plus_uconst)
+// block_len = 7;
+// }
+// }
//#endif
- reg_location.SetIsDWARFExpression(block_data, block_len);
- row->SetRegisterInfo (reg_num, reg_location);
- }
- break;
-
- case DW_CFA_val_offset : // 0x14
- case DW_CFA_val_offset_sf : // 0x15
- default:
- break;
+ reg_location.SetIsDWARFExpression(block_data, block_len);
+ row.SetRegisterInfo (reg_num, reg_location);
+ return true;
}
}
}
- unwind_plan.AppendRow(row);
-
- return true;
+ return false;
}
diff --git a/source/Symbol/FuncUnwinders.cpp b/source/Symbol/FuncUnwinders.cpp
index 1eb73ee3649b..000df722bb9e 100644
--- a/source/Symbol/FuncUnwinders.cpp
+++ b/source/Symbol/FuncUnwinders.cpp
@@ -145,39 +145,27 @@ FuncUnwinders::GetEHFrameAugmentedUnwindPlan (Target &target, Thread &thread, in
Mutex::Locker lock (m_mutex);
m_tried_unwind_plan_eh_frame_augmented = true;
- if (m_range.GetBaseAddress().IsValid())
+ UnwindPlanSP eh_frame_plan = GetEHFrameUnwindPlan (target, current_offset);
+ if (!eh_frame_plan)
+ return m_unwind_plan_eh_frame_augmented_sp;
+
+ m_unwind_plan_eh_frame_augmented_sp.reset(new UnwindPlan(*eh_frame_plan));
+
+ // Augment the eh_frame instructions with epilogue descriptions if necessary so the
+ // UnwindPlan can be used at any instruction in the function.
+
+ UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
+ if (assembly_profiler_sp)
{
- Address current_pc (m_range.GetBaseAddress ());
- if (current_offset != -1)
- current_pc.SetOffset (current_pc.GetOffset() + current_offset);
- DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
- if (eh_frame)
+ if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite (m_range, thread, *m_unwind_plan_eh_frame_augmented_sp))
{
- m_unwind_plan_eh_frame_augmented_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
- if (!eh_frame->GetUnwindPlan (current_pc, *m_unwind_plan_eh_frame_augmented_sp))
- {
- m_unwind_plan_eh_frame_augmented_sp.reset();
- }
- else
- {
- // Augment the eh_frame instructions with epilogue descriptions if necessary so the
- // UnwindPlan can be used at any instruction in the function.
-
- UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
- if (assembly_profiler_sp)
- {
- if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite (m_range, thread, *m_unwind_plan_eh_frame_augmented_sp))
- {
- m_unwind_plan_eh_frame_augmented_sp.reset();
- }
- }
- else
- {
- m_unwind_plan_eh_frame_augmented_sp.reset();
- }
- }
+ m_unwind_plan_eh_frame_augmented_sp.reset();
}
}
+ else
+ {
+ m_unwind_plan_eh_frame_augmented_sp.reset();
+ }
return m_unwind_plan_eh_frame_augmented_sp;
}
@@ -191,7 +179,7 @@ FuncUnwinders::GetAssemblyUnwindPlan (Target &target, Thread &thread, int curren
Mutex::Locker lock (m_mutex);
m_tried_unwind_plan_assembly = true;
- UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
+ UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp)
{
m_unwind_plan_assembly_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
@@ -216,7 +204,7 @@ FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int c
}
UnwindPlanSP
-FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
+FuncUnwinders::GetUnwindPlanFastUnwind (Target& target, Thread& thread)
{
if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast)
return m_unwind_plan_fast_sp;
@@ -224,7 +212,7 @@ FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
Mutex::Locker locker (m_mutex);
m_tried_unwind_fast = true;
- UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
+ UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp)
{
m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
@@ -299,7 +287,7 @@ FuncUnwinders::GetFirstNonPrologueInsn (Target& target)
Mutex::Locker locker (m_mutex);
ExecutionContext exe_ctx (target.shared_from_this(), false);
- UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
+ UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp)
assembly_profiler_sp->FirstNonPrologueInsn (m_range, exe_ctx, m_first_non_prologue_insn);
return m_first_non_prologue_insn;
@@ -312,12 +300,13 @@ FuncUnwinders::GetFunctionStartAddress () const
}
lldb::UnwindAssemblySP
-FuncUnwinders::GetUnwindAssemblyProfiler ()
+FuncUnwinders::GetUnwindAssemblyProfiler (Target& target)
{
UnwindAssemblySP assembly_profiler_sp;
ArchSpec arch;
if (m_unwind_table.GetArchitecture (arch))
{
+ arch.MergeFrom (target.GetArchitecture ());
assembly_profiler_sp = UnwindAssembly::FindPlugin (arch);
}
return assembly_profiler_sp;
diff --git a/source/Symbol/LineTable.cpp b/source/Symbol/LineTable.cpp
index 92b243d80a91..3b951f567660 100644
--- a/source/Symbol/LineTable.cpp
+++ b/source/Symbol/LineTable.cpp
@@ -542,8 +542,7 @@ LineTable::LinkLineTable (const FileRangeMap &file_range_map)
// This entry doesn't have a remapping and it needs to be removed.
// Watch out in case we need to terminate a previous entry needs to
// be terminated now that one line entry in a sequence is not longer valid.
- if (!entry.is_terminal_entry &&
- !sequence.m_entries.empty() &&
+ if (!sequence.m_entries.empty() &&
!sequence.m_entries.back().is_terminal_entry)
{
terminate_previous_entry = true;
diff --git a/source/Symbol/ObjectFile.cpp b/source/Symbol/ObjectFile.cpp
index c24e83260d4d..22a313cf6a20 100644
--- a/source/Symbol/ObjectFile.cpp
+++ b/source/Symbol/ObjectFile.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "lldb/lldb-private.h"
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/DataBuffer.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Log.h"
@@ -329,7 +328,7 @@ ObjectFile::GetAddressClass (addr_t file_addr)
{
if (symbol->ValueIsAddress())
{
- const SectionSP section_sp (symbol->GetAddress().GetSection());
+ const SectionSP section_sp (symbol->GetAddressRef().GetSection());
if (section_sp)
{
const SectionType section_type = section_sp->GetType();
diff --git a/source/Symbol/Symbol.cpp b/source/Symbol/Symbol.cpp
index b6ed94610b0a..dff15dd92613 100644
--- a/source/Symbol/Symbol.cpp
+++ b/source/Symbol/Symbol.cpp
@@ -36,6 +36,7 @@ Symbol::Symbol() :
m_size_is_synthesized (false),
m_size_is_valid (false),
m_demangled_is_synthesized (false),
+ m_contains_linker_annotations (false),
m_type (eSymbolTypeInvalid),
m_mangled (),
m_addr_range (),
@@ -57,6 +58,7 @@ Symbol::Symbol
addr_t offset,
addr_t size,
bool size_is_valid,
+ bool contains_linker_annotations,
uint32_t flags
) :
SymbolContextScope (),
@@ -70,6 +72,7 @@ Symbol::Symbol
m_size_is_synthesized (false),
m_size_is_valid (size_is_valid || size > 0),
m_demangled_is_synthesized (false),
+ m_contains_linker_annotations (contains_linker_annotations),
m_type (type),
m_mangled (ConstString(name), name_is_mangled),
m_addr_range (section_sp, offset, size),
@@ -80,8 +83,7 @@ Symbol::Symbol
Symbol::Symbol
(
uint32_t symID,
- const char *name,
- bool name_is_mangled,
+ const Mangled &mangled,
SymbolType type,
bool external,
bool is_debug,
@@ -89,6 +91,7 @@ Symbol::Symbol
bool is_artificial,
const AddressRange &range,
bool size_is_valid,
+ bool contains_linker_annotations,
uint32_t flags
) :
SymbolContextScope (),
@@ -102,8 +105,9 @@ Symbol::Symbol
m_size_is_synthesized (false),
m_size_is_valid (size_is_valid || range.GetByteSize() > 0),
m_demangled_is_synthesized (false),
+ m_contains_linker_annotations (contains_linker_annotations),
m_type (type),
- m_mangled (ConstString(name), name_is_mangled),
+ m_mangled (mangled),
m_addr_range (range),
m_flags (flags)
{
@@ -121,6 +125,7 @@ Symbol::Symbol(const Symbol& rhs):
m_size_is_synthesized (false),
m_size_is_valid (rhs.m_size_is_valid),
m_demangled_is_synthesized (rhs.m_demangled_is_synthesized),
+ m_contains_linker_annotations (rhs.m_contains_linker_annotations),
m_type (rhs.m_type),
m_mangled (rhs.m_mangled),
m_addr_range (rhs.m_addr_range),
@@ -144,6 +149,7 @@ Symbol::operator= (const Symbol& rhs)
m_size_is_synthesized = rhs.m_size_is_sibling;
m_size_is_valid = rhs.m_size_is_valid;
m_demangled_is_synthesized = rhs.m_demangled_is_synthesized;
+ m_contains_linker_annotations = rhs.m_contains_linker_annotations;
m_type = rhs.m_type;
m_mangled = rhs.m_mangled;
m_addr_range = rhs.m_addr_range;
@@ -166,6 +172,7 @@ Symbol::Clear()
m_size_is_synthesized = false;
m_size_is_valid = false;
m_demangled_is_synthesized = false;
+ m_contains_linker_annotations = false;
m_type = eSymbolTypeInvalid;
m_flags = 0;
m_addr_range.Clear();
@@ -209,18 +216,13 @@ Symbol::GetReExportedSymbolSharedLibrary() const
return FileSpec();
}
-bool
+void
Symbol::SetReExportedSymbolName(const ConstString &name)
{
- if (m_type == eSymbolTypeReExported)
- {
- // For eSymbolTypeReExported, the "const char *" from a ConstString
- // is used as the offset in the address range base address.
- m_addr_range.GetBaseAddress().SetOffset((intptr_t)name.GetCString());
- return true;
- }
- return false;
-
+ SetType (eSymbolTypeReExported);
+ // For eSymbolTypeReExported, the "const char *" from a ConstString
+ // is used as the offset in the address range base address.
+ m_addr_range.GetBaseAddress().SetOffset((uintptr_t)name.GetCString());
}
bool
@@ -230,7 +232,7 @@ Symbol::SetReExportedSymbolSharedLibrary(const FileSpec &fspec)
{
// For eSymbolTypeReExported, the "const char *" from a ConstString
// is used as the offset in the address range base address.
- m_addr_range.SetByteSize((intptr_t)ConstString(fspec.GetPath().c_str()).GetCString());
+ m_addr_range.SetByteSize((uintptr_t)ConstString(fspec.GetPath().c_str()).GetCString());
return true;
}
return false;
@@ -240,7 +242,7 @@ Symbol::SetReExportedSymbolSharedLibrary(const FileSpec &fspec)
uint32_t
Symbol::GetSiblingIndex() const
{
- return m_size_is_sibling ? m_addr_range.GetByteSize() : 0;
+ return m_size_is_sibling ? m_addr_range.GetByteSize() : UINT32_MAX;
}
bool
@@ -296,10 +298,7 @@ Symbol::GetDescription (Stream *s, lldb::DescriptionLevel level, Target *target)
void
Symbol::Dump(Stream *s, Target *target, uint32_t index) const
{
-// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
-// s->Indent();
-// s->Printf("Symbol[%5u] %6u %c%c %-12s ",
- s->Printf("[%5u] %6u %c%c%c %-12s ",
+ s->Printf("[%5u] %6u %c%c%c %-15s ",
index,
GetID(),
m_is_debug ? 'D' : ' ',
@@ -492,7 +491,7 @@ Symbol::CalculateSymbolContext (SymbolContext *sc)
// Symbols can reconstruct the symbol and the module in the symbol context
sc->symbol = this;
if (ValueIsAddress())
- sc->module_sp = GetAddress().GetModule();
+ sc->module_sp = GetAddressRef().GetModule();
else
sc->module_sp.reset();
}
@@ -501,7 +500,7 @@ ModuleSP
Symbol::CalculateSymbolContextModule ()
{
if (ValueIsAddress())
- return GetAddress().GetModule();
+ return GetAddressRef().GetModule();
return ModuleSP();
}
@@ -517,7 +516,7 @@ Symbol::DumpSymbolContext (Stream *s)
bool dumped_module = false;
if (ValueIsAddress())
{
- ModuleSP module_sp (GetAddress().GetModule());
+ ModuleSP module_sp (GetAddressRef().GetModule());
if (module_sp)
{
dumped_module = true;
@@ -619,6 +618,25 @@ Symbol::ResolveReExportedSymbol (Target &target) const
}
lldb::addr_t
+Symbol::GetFileAddress () const
+{
+ if (ValueIsAddress())
+ return GetAddressRef().GetFileAddress();
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+lldb::addr_t
+Symbol::GetLoadAddress (Target *target) const
+{
+ if (ValueIsAddress())
+ return GetAddressRef().GetLoadAddress(target);
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+
+lldb::addr_t
Symbol::ResolveCallableAddress(Target &target) const
{
if (GetType() == lldb::eSymbolTypeUndefined)
diff --git a/source/Symbol/SymbolContext.cpp b/source/Symbol/SymbolContext.cpp
index 62ae6ac464ce..8e4240a4587d 100644
--- a/source/Symbol/SymbolContext.cpp
+++ b/source/Symbol/SymbolContext.cpp
@@ -129,15 +129,15 @@ SymbolContext::Clear(bool clear_target)
}
bool
-SymbolContext::DumpStopContext
-(
+SymbolContext::DumpStopContext (
Stream *s,
ExecutionContextScope *exe_scope,
const Address &addr,
bool show_fullpaths,
bool show_module,
bool show_inlined_frames,
- bool show_function_arguments
+ bool show_function_arguments,
+ bool show_function_name
) const
{
bool dumped_something = false;
@@ -155,7 +155,12 @@ SymbolContext::DumpStopContext
{
SymbolContext inline_parent_sc;
Address inline_parent_addr;
- if (show_function_arguments == false && function->GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments))
+ if (show_function_name == false)
+ {
+ s->Printf("<");
+ dumped_something = true;
+ }
+ else if (show_function_arguments == false && function->GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments))
{
dumped_something = true;
function->GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments).Dump(s);
@@ -169,7 +174,13 @@ SymbolContext::DumpStopContext
if (addr.IsValid())
{
const addr_t function_offset = addr.GetOffset() - function->GetAddressRange().GetBaseAddress().GetOffset();
- if (function_offset)
+ if (show_function_name == false)
+ {
+ // Print +offset even if offset is 0
+ dumped_something = true;
+ s->Printf("+%" PRIu64 ">", function_offset);
+ }
+ else if (function_offset)
{
dumped_something = true;
s->Printf(" + %" PRIu64, function_offset);
@@ -202,7 +213,8 @@ SymbolContext::DumpStopContext
{
s->EOL();
s->Indent();
- return inline_parent_sc.DumpStopContext (s, exe_scope, inline_parent_addr, show_fullpaths, show_module, show_inlined_frames, show_function_arguments);
+ const bool show_function_name = true;
+ return inline_parent_sc.DumpStopContext (s, exe_scope, inline_parent_addr, show_fullpaths, show_module, show_inlined_frames, show_function_arguments, show_function_name);
}
}
else
@@ -218,7 +230,12 @@ SymbolContext::DumpStopContext
}
else if (symbol != nullptr)
{
- if (symbol->GetMangled().GetName())
+ if (show_function_name == false)
+ {
+ s->Printf("<");
+ dumped_something = true;
+ }
+ else if (symbol->GetMangled().GetName())
{
dumped_something = true;
if (symbol->GetType() == eSymbolTypeTrampoline)
@@ -228,8 +245,14 @@ SymbolContext::DumpStopContext
if (addr.IsValid() && symbol->ValueIsAddress())
{
- const addr_t symbol_offset = addr.GetOffset() - symbol->GetAddress().GetOffset();
- if (symbol_offset)
+ const addr_t symbol_offset = addr.GetOffset() - symbol->GetAddressRef().GetOffset();
+ if (show_function_name == false)
+ {
+ // Print +offset even if offset is 0
+ dumped_something = true;
+ s->Printf("+%" PRIu64 ">", symbol_offset);
+ }
+ else if (symbol_offset)
{
dumped_something = true;
s->Printf(" + %" PRIu64, symbol_offset);
@@ -492,7 +515,7 @@ SymbolContext::GetAddressRange (uint32_t scope,
{
if (symbol->ValueIsAddress())
{
- range.GetBaseAddress() = symbol->GetAddress();
+ range.GetBaseAddress() = symbol->GetAddressRef();
range.SetByteSize (symbol->GetByteSize());
return true;
}
@@ -1083,7 +1106,7 @@ SymbolContextList::AppendIfUnique (const SymbolContext& sc, bool merge_symbol_in
if (pos->function)
{
- if (pos->function->GetAddressRange().GetBaseAddress() == sc.symbol->GetAddress())
+ if (pos->function->GetAddressRange().GetBaseAddress() == sc.symbol->GetAddressRef())
{
// Do we already have a function with this symbol?
if (pos->symbol == sc.symbol)
@@ -1125,7 +1148,7 @@ SymbolContextList::MergeSymbolContextIntoFunctionContext (const SymbolContext& s
if (function_sc.function)
{
- if (function_sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddress())
+ if (function_sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRef())
{
// Do we already have a function with this symbol?
if (function_sc.symbol == symbol_sc.symbol)
diff --git a/source/Symbol/SymbolVendor.cpp b/source/Symbol/SymbolVendor.cpp
index a3f4104016e5..6ec9f3861ecf 100644
--- a/source/Symbol/SymbolVendor.cpp
+++ b/source/Symbol/SymbolVendor.cpp
@@ -198,6 +198,21 @@ SymbolVendor::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecLis
return false;
}
+bool
+SymbolVendor::ParseImportedModules (const SymbolContext &sc,
+ std::vector<ConstString> &imported_modules)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseImportedModules(sc, imported_modules);
+ }
+ return false;
+
+}
+
size_t
SymbolVendor::ParseFunctionBlocks (const SymbolContext &sc)
{
@@ -380,6 +395,8 @@ SymbolVendor::Dump(Stream *s)
ModuleSP module_sp(GetModule());
if (module_sp)
{
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+
bool show_context = false;
s->Printf("%p: ", static_cast<void*>(this));
@@ -423,6 +440,7 @@ SymbolVendor::GetCompileUnitAtIndex(size_t idx)
ModuleSP module_sp(GetModule());
if (module_sp)
{
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
const size_t num_compile_units = GetNumCompileUnits();
if (idx < num_compile_units)
{
@@ -437,6 +455,19 @@ SymbolVendor::GetCompileUnitAtIndex(size_t idx)
return cu_sp;
}
+FileSpec
+SymbolVendor::GetMainFileSpec() const
+{
+ if (m_sym_file_ap.get())
+ {
+ const ObjectFile *symfile_objfile = m_sym_file_ap->GetObjectFile();
+ if (symfile_objfile)
+ return symfile_objfile->GetFileSpec();
+ }
+
+ return FileSpec();
+}
+
Symtab *
SymbolVendor::GetSymtab ()
{
diff --git a/source/Symbol/Symtab.cpp b/source/Symbol/Symtab.cpp
index 907072c0d906..4cc03345d05b 100644
--- a/source/Symbol/Symtab.cpp
+++ b/source/Symbol/Symtab.cpp
@@ -14,6 +14,7 @@
#include "lldb/Core/Section.h"
#include "lldb/Core/Timer.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Symtab.h"
#include "lldb/Target/CPPLanguageRuntime.h"
@@ -201,16 +202,16 @@ Symtab::DumpSymbolHeader (Stream *s)
s->Indent(" |Synthetic symbol\n");
s->Indent(" ||Externally Visible\n");
s->Indent(" |||\n");
- s->Indent("Index UserID DSX Type File Address/Value Load Address Size Flags Name\n");
- s->Indent("------- ------ --- ------------ ------------------ ------------------ ------------------ ---------- ----------------------------------\n");
+ s->Indent("Index UserID DSX Type File Address/Value Load Address Size Flags Name\n");
+ s->Indent("------- ------ --- --------------- ------------------ ------------------ ------------------ ---------- ----------------------------------\n");
}
static int
CompareSymbolID (const void *key, const void *p)
{
- const user_id_t match_uid = *(user_id_t*) key;
- const user_id_t symbol_uid = ((Symbol *)p)->GetID();
+ const user_id_t match_uid = *(const user_id_t*) key;
+ const user_id_t symbol_uid = ((const Symbol *)p)->GetID();
if (match_uid < symbol_uid)
return -1;
if (match_uid > symbol_uid)
@@ -226,7 +227,7 @@ Symtab::FindSymbolByID (lldb::user_id_t symbol_uid) const
Symbol *symbol = (Symbol*)::bsearch (&symbol_uid,
&m_symbols[0],
m_symbols.size(),
- (uint8_t *)&m_symbols[1] - (uint8_t *)&m_symbols[0],
+ sizeof(m_symbols[0]),
CompareSymbolID);
return symbol;
}
@@ -312,6 +313,13 @@ Symtab::InitNameIndexes()
if (entry.cstring && entry.cstring[0])
{
m_name_to_index.Append (entry);
+
+ if (symbol->ContainsLinkerAnnotations()) {
+ // If the symbol has linker annotations, also add the version without the
+ // annotations.
+ entry.cstring = ConstString(m_objfile->StripLinkerSymbolAnnotations(entry.cstring)).GetCString();
+ m_name_to_index.Append (entry);
+ }
const SymbolType symbol_type = symbol->GetType();
if (symbol_type == eSymbolTypeCode || symbol_type == eSymbolTypeResolver)
@@ -371,8 +379,16 @@ Symtab::InitNameIndexes()
}
entry.cstring = mangled.GetDemangledName().GetCString();
- if (entry.cstring && entry.cstring[0])
+ if (entry.cstring && entry.cstring[0]) {
m_name_to_index.Append (entry);
+
+ if (symbol->ContainsLinkerAnnotations()) {
+ // If the symbol has linker annotations, also add the version without the
+ // annotations.
+ entry.cstring = ConstString(m_objfile->StripLinkerSymbolAnnotations(entry.cstring)).GetCString();
+ m_name_to_index.Append (entry);
+ }
+ }
// If the demangled name turns out to be an ObjC name, and
// is a category name, add the version without categories to the index too.
@@ -546,9 +562,12 @@ Symtab::AppendSymbolIndexesWithType (SymbolType symbol_type, Debug symbol_debug_
uint32_t
Symtab::GetIndexForSymbol (const Symbol *symbol) const
{
- const Symbol *first_symbol = &m_symbols[0];
- if (symbol >= first_symbol && symbol < first_symbol + m_symbols.size())
- return symbol - first_symbol;
+ if (!m_symbols.empty())
+ {
+ const Symbol *first_symbol = &m_symbols[0];
+ if (symbol >= first_symbol && symbol < first_symbol + m_symbols.size())
+ return symbol - first_symbol;
+ }
return UINT32_MAX;
}
@@ -579,14 +598,14 @@ namespace {
addr_t value_a = addr_cache[index_a];
if (value_a == LLDB_INVALID_ADDRESS)
{
- value_a = symbols[index_a].GetAddress().GetFileAddress();
+ value_a = symbols[index_a].GetAddressRef().GetFileAddress();
addr_cache[index_a] = value_a;
}
addr_t value_b = addr_cache[index_b];
if (value_b == LLDB_INVALID_ADDRESS)
{
- value_b = symbols[index_b].GetAddress().GetFileAddress();
+ value_b = symbols[index_b].GetAddressRef().GetFileAddress();
addr_cache[index_b] = value_b;
}
@@ -883,7 +902,7 @@ SymbolWithClosestFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr)
const addr_t info_file_addr = info->file_addr;
if (symbol->ValueIsAddress())
{
- const addr_t curr_file_addr = symbol->GetAddress().GetFileAddress();
+ const addr_t curr_file_addr = symbol->GetAddressRef().GetFileAddress();
if (info_file_addr < curr_file_addr)
return -1;
@@ -917,7 +936,7 @@ Symtab::InitAddressIndexes()
{
if (pos->ValueIsAddress())
{
- entry.SetRangeBase(pos->GetAddress().GetFileAddress());
+ entry.SetRangeBase(pos->GetAddressRef().GetFileAddress());
entry.SetByteSize(pos->GetByteSize());
entry.data = std::distance(begin, pos);
m_file_addr_to_index.Append(entry);
@@ -1178,3 +1197,20 @@ Symtab::FindFunctionSymbols (const ConstString &name,
return count;
}
+
+const Symbol *
+Symtab::GetParent (Symbol *child_symbol) const
+{
+ uint32_t child_idx = GetIndexForSymbol(child_symbol);
+ if (child_idx != UINT32_MAX && child_idx > 0)
+ {
+ for (uint32_t idx = child_idx - 1; idx != UINT32_MAX; --idx)
+ {
+ const Symbol *symbol = SymbolAtIndex (idx);
+ const uint32_t sibling_idx = symbol->GetSiblingIndex();
+ if (sibling_idx != UINT32_MAX && sibling_idx > child_idx)
+ return symbol;
+ }
+ }
+ return NULL;
+}
diff --git a/source/Symbol/Type.cpp b/source/Symbol/Type.cpp
index 6e67f4695d9f..0927d55f1ee2 100644
--- a/source/Symbol/Type.cpp
+++ b/source/Symbol/Type.cpp
@@ -589,16 +589,27 @@ Type::ResolveClangType (ResolveState clang_type_resolve_state)
break;
}
}
+
+ // When we have a EncodingUID, our "m_flags.clang_type_resolve_state" is set to eResolveStateUnresolved
+ // so we need to update it to say that we now have a forward declaration since that is what we created
+ // above.
+ if (m_clang_type.IsValid())
+ m_flags.clang_type_resolve_state = eResolveStateForward;
+
}
-
+
// Check if we have a forward reference to a class/struct/union/enum?
- if (m_clang_type.IsValid() && m_flags.clang_type_resolve_state < clang_type_resolve_state)
+ if (clang_type_resolve_state == eResolveStateLayout || clang_type_resolve_state == eResolveStateFull)
{
- m_flags.clang_type_resolve_state = eResolveStateFull;
- if (!m_clang_type.IsDefined ())
+ // Check if we have a forward reference to a class/struct/union/enum?
+ if (m_clang_type.IsValid() && m_flags.clang_type_resolve_state < clang_type_resolve_state)
{
- // We have a forward declaration, we need to resolve it to a complete definition.
- m_symbol_file->ResolveClangOpaqueTypeDefinition (m_clang_type);
+ m_flags.clang_type_resolve_state = eResolveStateFull;
+ if (!m_clang_type.IsDefined ())
+ {
+ // We have a forward declaration, we need to resolve it to a complete definition.
+ m_symbol_file->ResolveClangOpaqueTypeDefinition (m_clang_type);
+ }
}
}
diff --git a/source/Symbol/UnwindPlan.cpp b/source/Symbol/UnwindPlan.cpp
index 87d0f49421c5..80c22c08ee4f 100644
--- a/source/Symbol/UnwindPlan.cpp
+++ b/source/Symbol/UnwindPlan.cpp
@@ -94,31 +94,7 @@ UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_pla
s.PutChar('=');
if (m_type == atCFAPlusOffset)
s.PutChar('[');
- if (verbose)
- s.Printf ("CFA%+d", m_location.offset);
-
- if (unwind_plan && row)
- {
- const uint32_t cfa_reg = row->GetCFARegister();
- const RegisterInfo *cfa_reg_info = unwind_plan->GetRegisterInfo (thread, cfa_reg);
- const int32_t offset = row->GetCFAOffset() + m_location.offset;
- if (verbose)
- {
- if (cfa_reg_info)
- s.Printf (" (%s%+d)", cfa_reg_info->name, offset);
- else
- s.Printf (" (reg(%u)%+d)", cfa_reg, offset);
- }
- else
- {
- if (cfa_reg_info)
- s.Printf ("%s", cfa_reg_info->name);
- else
- s.Printf ("reg(%u)", cfa_reg);
- if (offset != 0)
- s.Printf ("%+d", offset);
- }
- }
+ s.Printf ("CFA%+d", m_location.offset);
if (m_type == atCFAPlusOffset)
s.PutChar(']');
}
@@ -150,38 +126,83 @@ UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_pla
}
}
+static void
+DumpRegisterName (Stream &s, const UnwindPlan* unwind_plan, Thread *thread, uint32_t reg_num) {
+ const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, reg_num);
+ if (reg_info)
+ s.PutCString (reg_info->name);
+ else
+ s.Printf ("reg(%u)", reg_num);
+}
+
+bool
+UnwindPlan::Row::CFAValue::operator == (const UnwindPlan::Row::CFAValue& rhs) const
+{
+ if (m_type == rhs.m_type)
+ {
+ switch (m_type)
+ {
+ case unspecified:
+ return true;
+
+ case isRegisterPlusOffset:
+ return m_value.reg.offset == rhs.m_value.reg.offset;
+
+ case isRegisterDereferenced:
+ return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
+
+ case isDWARFExpression:
+ if (m_value.expr.length == rhs.m_value.expr.length)
+ return !memcmp (m_value.expr.opcodes, rhs.m_value.expr.opcodes, m_value.expr.length);
+ break;
+ }
+ }
+ return false;
+}
+
+void
+UnwindPlan::Row::CFAValue::Dump(Stream &s, const UnwindPlan* unwind_plan, Thread* thread) const
+{
+ switch(m_type) {
+ case isRegisterPlusOffset:
+ DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
+ s.Printf ("%+3d", m_value.reg.offset);
+ break;
+ case isRegisterDereferenced:
+ s.PutChar ('[');
+ DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
+ s.PutChar (']');
+ break;
+ case isDWARFExpression:
+ s.PutCString ("dwarf-expr");
+ break;
+ default:
+ s.PutCString ("unspecified");
+ break;
+ }
+}
+
void
UnwindPlan::Row::Clear ()
{
- m_cfa_type = CFAIsRegisterPlusOffset;
+ m_cfa_value.SetUnspecified();
m_offset = 0;
- m_cfa_reg_num = LLDB_INVALID_REGNUM;
- m_cfa_offset = 0;
m_register_locations.clear();
}
void
UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const
{
- const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister());
-
if (base_addr != LLDB_INVALID_ADDRESS)
s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
else
s.Printf ("%4" PRId64 ": CFA=", GetOffset());
- if (reg_info)
- s.Printf ("%s", reg_info->name);
- else
- s.Printf ("reg(%u)", GetCFARegister());
- s.Printf ("%+3d => ", GetCFAOffset ());
+ m_cfa_value.Dump(s, unwind_plan, thread);
+ s.Printf(" => ");
for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
{
- reg_info = unwind_plan->GetRegisterInfo (thread, idx->first);
- if (reg_info)
- s.Printf ("%s", reg_info->name);
- else
- s.Printf ("reg(%u)", idx->first);
+ DumpRegisterName(s, unwind_plan, thread, idx->first);
const bool verbose = false;
idx->second.Dump(s, unwind_plan, this, thread, verbose);
s.PutChar (' ');
@@ -191,9 +212,7 @@ UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread,
UnwindPlan::Row::Row() :
m_offset (0),
- m_cfa_type (CFAIsRegisterPlusOffset),
- m_cfa_reg_num (LLDB_INVALID_REGNUM),
- m_cfa_offset (0),
+ m_cfa_value (),
m_register_locations ()
{
}
@@ -302,35 +321,11 @@ UnwindPlan::Row::SetRegisterLocationToSame (uint32_t reg_num, bool must_replace)
return true;
}
-void
-UnwindPlan::Row::SetCFARegister (uint32_t reg_num)
-{
- m_cfa_reg_num = reg_num;
-}
-
bool
UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const
{
- if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset)
- return false;
-
- if (m_cfa_type != rhs.m_cfa_type)
- return false;
-
- if (m_cfa_type == CFAIsRegisterPlusOffset)
- {
- if (m_cfa_reg_num != rhs.m_cfa_reg_num)
- return false;
- if (m_cfa_offset != rhs.m_cfa_offset)
- return false;
- }
- if (m_cfa_type == CFAIsRegisterDereferenced)
- {
- if (m_cfa_reg_num != rhs.m_cfa_reg_num)
- return false;
- }
-
- return m_register_locations == rhs.m_register_locations;
+ return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
+ m_register_locations == rhs.m_register_locations;
}
void
@@ -348,11 +343,12 @@ 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())
+ if (row->GetOffset() >= row_sp->GetOffset())
break;
it++;
}
- m_row_list.insert(it, row_sp);
+ if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
+ m_row_list.insert(it, row_sp);
}
UnwindPlan::RowSP
@@ -439,7 +435,8 @@ 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() == nullptr || GetRowAtIndex(0)->GetCFARegister() == LLDB_INVALID_REGNUM)
+ if (GetRowAtIndex(0).get() == nullptr ||
+ GetRowAtIndex(0)->GetCFAValue().GetValueType() == Row::CFAValue::unspecified)
{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
if (log)
diff --git a/source/Symbol/Variable.cpp b/source/Symbol/Variable.cpp
index 4c03a307296d..5665e4702ca6 100644
--- a/source/Symbol/Variable.cpp
+++ b/source/Symbol/Variable.cpp
@@ -36,7 +36,7 @@ Variable::Variable
(
lldb::user_id_t uid,
const char *name,
- const char *mangled, // The mangled variable name for variables in namespaces
+ const char *mangled, // The mangled or fully qualified name of the variable.
const lldb::SymbolFileTypeSP &symfile_type_sp,
ValueType scope,
SymbolContextScope *context,
@@ -47,7 +47,7 @@ Variable::Variable
) :
UserID(uid),
m_name(name),
- m_mangled (ConstString(mangled), true),
+ m_mangled (ConstString(mangled)),
m_symfile_type_sp(symfile_type_sp),
m_scope(scope),
m_owner_scope(context),
@@ -69,8 +69,9 @@ Variable::~Variable()
const ConstString&
Variable::GetName() const
{
- if (m_mangled)
- return m_mangled.GetName();
+ const ConstString &name = m_mangled.GetName();
+ if (name)
+ return name;
return m_name;
}
@@ -175,6 +176,7 @@ Variable::DumpDeclaration (Stream *s, bool show_fullpaths, bool show_module)
sc.line_entry.Clear();
bool show_inlined_frames = false;
const bool show_function_arguments = true;
+ const bool show_function_name = true;
dumped_declaration_info = sc.DumpStopContext (s,
nullptr,
@@ -182,7 +184,8 @@ Variable::DumpDeclaration (Stream *s, bool show_fullpaths, bool show_module)
show_fullpaths,
show_module,
show_inlined_frames,
- show_function_arguments);
+ show_function_arguments,
+ show_function_name);
if (sc.function)
s->PutChar(':');
diff --git a/source/Target/ABI.cpp b/source/Target/ABI.cpp
index e02f360680fb..8809c1e51d0c 100644
--- a/source/Target/ABI.cpp
+++ b/source/Target/ABI.cpp
@@ -11,6 +11,7 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
diff --git a/source/Target/ExecutionContext.cpp b/source/Target/ExecutionContext.cpp
index e03a560bd063..03714728559c 100644
--- a/source/Target/ExecutionContext.cpp
+++ b/source/Target/ExecutionContext.cpp
@@ -119,31 +119,42 @@ ExecutionContext::ExecutionContext (const lldb::StackFrameWP &frame_wp) :
}
ExecutionContext::ExecutionContext (Target* t, bool fill_current_process_thread_frame) :
- m_target_sp (t->shared_from_this()),
+ m_target_sp (),
m_process_sp (),
m_thread_sp (),
m_frame_sp ()
{
- if (t && fill_current_process_thread_frame)
+ if (t)
{
- m_process_sp = t->GetProcessSP();
- if (m_process_sp)
+ m_target_sp = t->shared_from_this();
+ if (fill_current_process_thread_frame)
{
- m_thread_sp = m_process_sp->GetThreadList().GetSelectedThread();
- if (m_thread_sp)
- m_frame_sp = m_thread_sp->GetSelectedFrame();
+ m_process_sp = t->GetProcessSP();
+ if (m_process_sp)
+ {
+ m_thread_sp = m_process_sp->GetThreadList().GetSelectedThread();
+ if (m_thread_sp)
+ m_frame_sp = m_thread_sp->GetSelectedFrame();
+ }
}
}
}
ExecutionContext::ExecutionContext(Process* process, Thread *thread, StackFrame *frame) :
m_target_sp (),
- m_process_sp (process->shared_from_this()),
- m_thread_sp (thread->shared_from_this()),
- m_frame_sp (frame->shared_from_this())
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
{
if (process)
+ {
+ m_process_sp = process->shared_from_this();
m_target_sp = process->GetTarget().shared_from_this();
+ }
+ if (thread)
+ m_thread_sp = thread->shared_from_this();
+ if (frame)
+ m_frame_sp = frame->shared_from_this();
}
ExecutionContext::ExecutionContext (const ExecutionContextRef &exe_ctx_ref) :
@@ -238,9 +249,9 @@ uint32_t
ExecutionContext::GetAddressByteSize() const
{
if (m_target_sp && m_target_sp->GetArchitecture().IsValid())
- m_target_sp->GetArchitecture().GetAddressByteSize();
+ return m_target_sp->GetArchitecture().GetAddressByteSize();
if (m_process_sp)
- m_process_sp->GetAddressByteSize();
+ return m_process_sp->GetAddressByteSize();
return sizeof(void *);
}
diff --git a/source/Target/FileAction.cpp b/source/Target/FileAction.cpp
index 8611ff5f2d2c..21c37e8e6f85 100644
--- a/source/Target/FileAction.cpp
+++ b/source/Target/FileAction.cpp
@@ -26,7 +26,7 @@ FileAction::FileAction() :
m_action(eFileActionNone),
m_fd(-1),
m_arg(-1),
- m_path()
+ m_file_spec()
{
}
@@ -36,21 +36,25 @@ FileAction::Clear()
m_action = eFileActionNone;
m_fd = -1;
m_arg = -1;
- m_path.clear();
+ m_file_spec.Clear();
}
const char *
FileAction::GetPath() const
{
- if (m_path.empty())
- return NULL;
- return m_path.c_str();
+ return m_file_spec.GetCString();
+}
+
+const FileSpec &
+FileAction::GetFileSpec() const
+{
+ return m_file_spec;
}
bool
-FileAction::Open(int fd, const char *path, bool read, bool write)
+FileAction::Open(int fd, const FileSpec &file_spec, bool read, bool write)
{
- if ((read || write) && fd >= 0 && path && path[0])
+ if ((read || write) && fd >= 0 && file_spec)
{
m_action = eFileActionOpen;
m_fd = fd;
@@ -60,7 +64,7 @@ FileAction::Open(int fd, const char *path, bool read, bool write)
m_arg = O_NOCTTY | O_RDONLY;
else
m_arg = O_NOCTTY | O_CREAT | O_WRONLY;
- m_path.assign(path);
+ m_file_spec = file_spec;
return true;
}
else
@@ -111,7 +115,8 @@ FileAction::Dump(Stream &stream) const
stream.PutCString("no action");
break;
case eFileActionOpen:
- stream.Printf("open fd %d with '%s', OFLAGS = 0x%x", m_fd, m_path.c_str(), m_arg);
+ stream.Printf("open fd %d with '%s', OFLAGS = 0x%x",
+ m_fd, m_file_spec.GetCString(), m_arg);
break;
}
}
diff --git a/source/Target/LanguageRuntime.cpp b/source/Target/LanguageRuntime.cpp
index 123ee93d322f..9c7b441d4c53 100644
--- a/source/Target/LanguageRuntime.cpp
+++ b/source/Target/LanguageRuntime.cpp
@@ -8,9 +8,11 @@
//===----------------------------------------------------------------------===//
#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/SearchFilter.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
using namespace lldb;
using namespace lldb_private;
@@ -277,6 +279,23 @@ LanguageRuntime::~LanguageRuntime()
{
}
+Breakpoint::BreakpointPreconditionSP
+LanguageRuntime::CreateExceptionPrecondition (lldb::LanguageType language,
+ bool catch_bp,
+ bool throw_bp)
+{
+ switch (language)
+ {
+ case eLanguageTypeObjC:
+ if (throw_bp)
+ return Breakpoint::BreakpointPreconditionSP(new ObjCLanguageRuntime::ObjCExceptionPrecondition ());
+ break;
+ default:
+ break;
+ }
+ return Breakpoint::BreakpointPreconditionSP();
+}
+
BreakpointSP
LanguageRuntime::CreateExceptionBreakpoint (Target &target,
lldb::LanguageType language,
@@ -289,8 +308,15 @@ LanguageRuntime::CreateExceptionBreakpoint (Target &target,
bool hardware = false;
bool resolve_indirect_functions = false;
BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware, resolve_indirect_functions));
- if (is_internal)
- exc_breakpt_sp->SetBreakpointKind("exception");
+ if (exc_breakpt_sp)
+ {
+ Breakpoint::BreakpointPreconditionSP precondition_sp = CreateExceptionPrecondition(language, catch_bp, throw_bp);
+ if (precondition_sp)
+ exc_breakpt_sp->SetPrecondition(precondition_sp);
+
+ if (is_internal)
+ exc_breakpt_sp->SetBreakpointKind("exception");
+ }
return exc_breakpt_sp;
}
@@ -340,6 +366,9 @@ struct language_name_pair language_names[] =
{ "c++14", eLanguageTypeC_plus_plus_14 },
{ "fortran03", eLanguageTypeFortran03 },
{ "fortran08", eLanguageTypeFortran08 },
+ // Vendor Extensions
+ { "mipsassem", eLanguageTypeMipsAssembler },
+ { "renderscript", eLanguageTypeExtRenderScript},
// Now synonyms, in arbitrary order
{ "objc", eLanguageTypeObjC },
{ "objc++", eLanguageTypeObjC_plus_plus }
@@ -367,6 +396,57 @@ LanguageRuntime::GetNameForLanguageType (LanguageType language)
return language_names[eLanguageTypeUnknown].name;
}
+void
+LanguageRuntime::PrintAllLanguages (Stream &s, const char *prefix, const char *suffix)
+{
+ for (uint32_t i = 1; i < num_languages; i++)
+ {
+ s.Printf("%s%s%s", prefix, language_names[i].name, suffix);
+ }
+}
+
+bool
+LanguageRuntime::LanguageIsCPlusPlus (LanguageType language)
+{
+ switch (language)
+ {
+ case eLanguageTypeC_plus_plus:
+ case eLanguageTypeC_plus_plus_03:
+ case eLanguageTypeC_plus_plus_11:
+ case eLanguageTypeC_plus_plus_14:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void
+LanguageRuntime::InitializeCommands (CommandObject* parent)
+{
+ if (!parent)
+ return;
+
+ if (!parent->IsMultiwordObject())
+ return;
+
+ LanguageRuntimeCreateInstance create_callback;
+
+ for (uint32_t idx = 0;
+ (create_callback = PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != nullptr;
+ ++idx)
+ {
+ if (LanguageRuntimeGetCommandObject command_callback =
+ PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex(idx))
+ {
+ CommandObjectSP command = command_callback(parent->GetCommandInterpreter());
+ if (command)
+ {
+ parent->LoadSubCommand(command->GetCommandName(), command);
+ }
+ }
+ }
+}
+
lldb::SearchFilterSP
LanguageRuntime::CreateExceptionSearchFilter ()
{
diff --git a/source/Target/Memory.cpp b/source/Target/Memory.cpp
index 934bc967b68b..e61b3ab91e7b 100644
--- a/source/Target/Memory.cpp
+++ b/source/Target/Memory.cpp
@@ -14,8 +14,9 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/State.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Core/State.h"
#include "lldb/Target/Process.h"
using namespace lldb;
@@ -25,11 +26,12 @@ using namespace lldb_private;
// MemoryCache constructor
//----------------------------------------------------------------------
MemoryCache::MemoryCache(Process &process) :
- m_process (process),
- m_cache_line_byte_size (process.GetMemoryCacheLineSize()),
m_mutex (Mutex::eMutexTypeRecursive),
- m_cache (),
- m_invalid_ranges ()
+ m_L1_cache (),
+ m_L2_cache (),
+ m_invalid_ranges (),
+ m_process (process),
+ m_L2_cache_line_byte_size (process.GetMemoryCacheLineSize())
{
}
@@ -44,10 +46,24 @@ void
MemoryCache::Clear(bool clear_invalid_ranges)
{
Mutex::Locker locker (m_mutex);
- m_cache.clear();
+ m_L1_cache.clear();
+ m_L2_cache.clear();
if (clear_invalid_ranges)
m_invalid_ranges.Clear();
- m_cache_line_byte_size = m_process.GetMemoryCacheLineSize();
+ m_L2_cache_line_byte_size = m_process.GetMemoryCacheLineSize();
+}
+
+void
+MemoryCache::AddL1CacheData(lldb::addr_t addr, const void *src, size_t src_len)
+{
+ AddL1CacheData(addr,DataBufferSP (new DataBufferHeap(DataBufferHeap(src, src_len))));
+}
+
+void
+MemoryCache::AddL1CacheData(lldb::addr_t addr, const DataBufferSP &data_buffer_sp)
+{
+ Mutex::Locker locker (m_mutex);
+ m_L1_cache[addr] = data_buffer_sp;
}
void
@@ -57,29 +73,44 @@ MemoryCache::Flush (addr_t addr, size_t size)
return;
Mutex::Locker locker (m_mutex);
- if (m_cache.empty())
- return;
- const uint32_t cache_line_byte_size = m_cache_line_byte_size;
- const addr_t end_addr = (addr + size - 1);
- const addr_t first_cache_line_addr = addr - (addr % cache_line_byte_size);
- const addr_t last_cache_line_addr = end_addr - (end_addr % cache_line_byte_size);
- // Watch for overflow where size will cause us to go off the end of the
- // 64 bit address space
- uint32_t num_cache_lines;
- if (last_cache_line_addr >= first_cache_line_addr)
- num_cache_lines = ((last_cache_line_addr - first_cache_line_addr)/cache_line_byte_size) + 1;
- else
- num_cache_lines = (UINT64_MAX - first_cache_line_addr + 1)/cache_line_byte_size;
-
- uint32_t cache_idx = 0;
- for (addr_t curr_addr = first_cache_line_addr;
- cache_idx < num_cache_lines;
- curr_addr += cache_line_byte_size, ++cache_idx)
+ // Erase any blocks from the L1 cache that intersect with the flush range
+ if (!m_L1_cache.empty())
{
- BlockMap::iterator pos = m_cache.find (curr_addr);
- if (pos != m_cache.end())
- m_cache.erase(pos);
+ AddrRange flush_range(addr, size);
+ BlockMap::iterator pos = m_L1_cache.lower_bound(addr);
+ while (pos != m_L1_cache.end())
+ {
+ AddrRange chunk_range(pos->first, pos->second->GetByteSize());
+ if (!chunk_range.DoesIntersect(flush_range))
+ break;
+ pos = m_L1_cache.erase(pos);
+ }
+ }
+
+ if (!m_L2_cache.empty())
+ {
+ const uint32_t cache_line_byte_size = m_L2_cache_line_byte_size;
+ const addr_t end_addr = (addr + size - 1);
+ const addr_t first_cache_line_addr = addr - (addr % cache_line_byte_size);
+ const addr_t last_cache_line_addr = end_addr - (end_addr % cache_line_byte_size);
+ // Watch for overflow where size will cause us to go off the end of the
+ // 64 bit address space
+ uint32_t num_cache_lines;
+ if (last_cache_line_addr >= first_cache_line_addr)
+ num_cache_lines = ((last_cache_line_addr - first_cache_line_addr)/cache_line_byte_size) + 1;
+ else
+ num_cache_lines = (UINT64_MAX - first_cache_line_addr + 1)/cache_line_byte_size;
+
+ uint32_t cache_idx = 0;
+ for (addr_t curr_addr = first_cache_line_addr;
+ cache_idx < num_cache_lines;
+ curr_addr += cache_line_byte_size, ++cache_idx)
+ {
+ BlockMap::iterator pos = m_L2_cache.find (curr_addr);
+ if (pos != m_L2_cache.end())
+ m_L2_cache.erase(pos);
+ }
}
}
@@ -122,6 +153,39 @@ MemoryCache::Read (addr_t addr,
{
size_t bytes_left = dst_len;
+ // Check the L1 cache for a range that contain the entire memory read.
+ // If we find a range in the L1 cache that does, we use it. Else we fall
+ // back to reading memory in m_L2_cache_line_byte_size byte sized chunks.
+ // The L1 cache contains chunks of memory that are not required to be
+ // m_L2_cache_line_byte_size bytes in size, so we don't try anything
+ // tricky when reading from them (no partial reads from the L1 cache).
+
+ Mutex::Locker locker(m_mutex);
+ if (!m_L1_cache.empty())
+ {
+ AddrRange read_range(addr, dst_len);
+ BlockMap::iterator pos = m_L1_cache.lower_bound(addr);
+ if (pos != m_L1_cache.end())
+ {
+ AddrRange chunk_range(pos->first, pos->second->GetByteSize());
+ bool match = chunk_range.Contains(read_range);
+ if (!match && pos != m_L1_cache.begin())
+ {
+ --pos;
+ chunk_range.SetRangeBase(pos->first);
+ chunk_range.SetByteSize(pos->second->GetByteSize());
+ match = chunk_range.Contains(read_range);
+ }
+
+ if (match)
+ {
+ memcpy(dst, pos->second->GetBytes() + addr - chunk_range.GetRangeBase(), dst_len);
+ return 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
@@ -129,19 +193,22 @@ MemoryCache::Read (addr_t addr,
// 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)
+ if (dst && dst_len > m_L2_cache_line_byte_size)
{
- return m_process.ReadMemoryFromInferior (addr, dst, dst_len, error);
+ size_t bytes_read = m_process.ReadMemoryFromInferior (addr, dst, dst_len, error);
+ // Add this non block sized range to the L1 cache if we actually read anything
+ if (bytes_read > 0)
+ AddL1CacheData(addr, dst, bytes_read);
+ return bytes_read;
}
if (dst && bytes_left > 0)
{
- const uint32_t cache_line_byte_size = m_cache_line_byte_size;
+ const uint32_t cache_line_byte_size = m_L2_cache_line_byte_size;
uint8_t *dst_buf = (uint8_t *)dst;
addr_t curr_addr = addr - (addr % cache_line_byte_size);
addr_t cache_offset = addr - curr_addr;
- Mutex::Locker locker (m_mutex);
-
+
while (bytes_left > 0)
{
if (m_invalid_ranges.FindEntryThatContains(curr_addr))
@@ -150,8 +217,8 @@ MemoryCache::Read (addr_t addr,
return dst_len - bytes_left;
}
- BlockMap::const_iterator pos = m_cache.find (curr_addr);
- BlockMap::const_iterator end = m_cache.end ();
+ BlockMap::const_iterator pos = m_L2_cache.find (curr_addr);
+ BlockMap::const_iterator end = m_L2_cache.end ();
if (pos != end)
{
@@ -208,7 +275,7 @@ MemoryCache::Read (addr_t addr,
if (process_bytes_read != cache_line_byte_size)
data_buffer_heap_ap->SetByteSize (process_bytes_read);
- m_cache[curr_addr] = DataBufferSP (data_buffer_heap_ap.release());
+ m_L2_cache[curr_addr] = DataBufferSP (data_buffer_heap_ap.release());
// We have read data and put it into the cache, continue through the
// loop again to get the data out of the cache...
}
diff --git a/source/Target/ObjCLanguageRuntime.cpp b/source/Target/ObjCLanguageRuntime.cpp
index 3d7a9021343a..e54dd5b4920a 100644
--- a/source/Target/ObjCLanguageRuntime.cpp
+++ b/source/Target/ObjCLanguageRuntime.cpp
@@ -15,6 +15,7 @@
#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
@@ -43,7 +44,6 @@ ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) :
m_complete_class_cache(),
m_negative_complete_class_cache()
{
-
}
bool
@@ -497,6 +497,18 @@ ObjCLanguageRuntime::GetDescriptorIterator (const ConstString &name)
return end;
}
+std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,ObjCLanguageRuntime::ISAToDescriptorIterator>
+ObjCLanguageRuntime::GetDescriptorIteratorPair (bool update_if_needed)
+{
+ if (update_if_needed)
+ UpdateISAToDescriptorMapIfNeeded();
+
+ return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
+ ObjCLanguageRuntime::ISAToDescriptorIterator>(
+ m_isa_to_descriptor.begin(),
+ m_isa_to_descriptor.end());
+}
+
ObjCLanguageRuntime::ObjCISA
ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa)
@@ -670,3 +682,36 @@ ObjCLanguageRuntime::GetTypeBitSize (const ClangASTType& clang_type,
return found;
}
+
+//------------------------------------------------------------------
+// Exception breakpoint Precondition class for ObjC:
+//------------------------------------------------------------------
+void
+ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(const char *class_name)
+{
+ m_class_names.insert(class_name);
+}
+
+ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition()
+{
+}
+
+bool
+ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(StoppointCallbackContext &context)
+{
+ return true;
+}
+
+void
+ObjCLanguageRuntime::ObjCExceptionPrecondition::DescribePrecondition(Stream &stream, lldb::DescriptionLevel level)
+{
+}
+
+Error
+ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(Args &args)
+{
+ Error error;
+ if (args.GetArgumentCount() > 0)
+ error.SetErrorString("The ObjC Exception breakpoint doesn't support extra options.");
+ return error;
+}
diff --git a/source/Target/Platform.cpp b/source/Target/Platform.cpp
index 09c9efc14b08..6758ecf7e22e 100644
--- a/source/Target/Platform.cpp
+++ b/source/Target/Platform.cpp
@@ -10,25 +10,47 @@
#include "lldb/Target/Platform.h"
// C Includes
+
// C++ Includes
+#include <algorithm>
+#include <fstream>
+#include <vector>
+
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointIDList.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/Property.h"
+#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Utils.h"
+#include "llvm/Support/FileSystem.h"
+
+#include "Utility/ModuleCache.h"
+
+// Define these constants from POSIX mman.h rather than include the file
+// so that they will be correct even when compiled on Linux.
+#define MAP_PRIVATE 2
+#define MAP_ANON 0x1000
using namespace lldb;
using namespace lldb_private;
-
+
+static uint32_t g_initialize_count = 0;
+
// Use a singleton function for g_local_platform_sp to avoid init
// constructors since LLDB is often part of a shared library
static PlatformSP&
@@ -44,6 +66,73 @@ Platform::GetHostPlatformName ()
return "host";
}
+namespace {
+
+ PropertyDefinition
+ g_properties[] =
+ {
+ { "use-module-cache" , OptionValue::eTypeBoolean , true, true, nullptr, nullptr, "Use module cache." },
+ { "module-cache-directory", OptionValue::eTypeFileSpec, true, 0 , nullptr, nullptr, "Root directory for cached modules." },
+ { nullptr , OptionValue::eTypeInvalid , false, 0, nullptr, nullptr, nullptr }
+ };
+
+ enum
+ {
+ ePropertyUseModuleCache,
+ ePropertyModuleCacheDirectory
+ };
+
+} // namespace
+
+
+ConstString
+PlatformProperties::GetSettingName ()
+{
+ static ConstString g_setting_name("platform");
+ return g_setting_name;
+}
+
+PlatformProperties::PlatformProperties ()
+{
+ m_collection_sp.reset (new OptionValueProperties (GetSettingName ()));
+ m_collection_sp->Initialize (g_properties);
+
+ auto module_cache_dir = GetModuleCacheDirectory ();
+ if (!module_cache_dir)
+ {
+ if (!HostInfo::GetLLDBPath (ePathTypeGlobalLLDBTempSystemDir, module_cache_dir))
+ module_cache_dir = FileSpec ("/tmp/lldb", false);
+ module_cache_dir.AppendPathComponent ("module_cache");
+ SetModuleCacheDirectory (module_cache_dir);
+ }
+}
+
+bool
+PlatformProperties::GetUseModuleCache () const
+{
+ const auto idx = ePropertyUseModuleCache;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (
+ nullptr, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+PlatformProperties::SetUseModuleCache (bool use_module_cache)
+{
+ return m_collection_sp->SetPropertyAtIndexAsBoolean (nullptr, ePropertyUseModuleCache, use_module_cache);
+}
+
+FileSpec
+PlatformProperties::GetModuleCacheDirectory () const
+{
+ return m_collection_sp->GetPropertyAtIndexAsFileSpec (nullptr, ePropertyModuleCacheDirectory);
+}
+
+bool
+PlatformProperties::SetModuleCacheDirectory (const FileSpec& dir_spec)
+{
+ return m_collection_sp->SetPropertyAtIndexAsFileSpec (nullptr, ePropertyModuleCacheDirectory, dir_spec);
+}
+
//------------------------------------------------------------------
/// Get the native host platform plug-in.
///
@@ -75,6 +164,32 @@ GetPlatformListMutex ()
}
void
+Platform::Initialize ()
+{
+ g_initialize_count++;
+}
+
+void
+Platform::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ Mutex::Locker locker(GetPlatformListMutex ());
+ GetPlatformList().clear();
+ }
+ }
+}
+
+const PlatformPropertiesSP &
+Platform::GetGlobalPlatformProperties ()
+{
+ static const auto g_settings_sp (std::make_shared<PlatformProperties> ());
+ return g_settings_sp;
+}
+
+void
Platform::SetHostPlatform (const lldb::PlatformSP &platform_sp)
{
// The native platform should use its static void Platform::Initialize()
@@ -137,25 +252,43 @@ Platform::LocateExecutableScriptingResources (Target *target, Module &module, St
Error
Platform::GetSharedModule (const ModuleSpec &module_spec,
+ Process* process,
ModuleSP &module_sp,
const FileSpecList *module_search_paths_ptr,
ModuleSP *old_module_sp_ptr,
bool *did_create_ptr)
{
- // Don't do any path remapping for the default implementation
- // of the platform GetSharedModule function, just call through
- // to our static ModuleList function. Platform subclasses that
- // implement remote debugging, might have a developer kits
- // installed that have cached versions of the files for the
- // remote target, or might implement a download and cache
- // locally implementation.
- const bool always_create = false;
- return ModuleList::GetSharedModule (module_spec,
- module_sp,
- module_search_paths_ptr,
- old_module_sp_ptr,
- did_create_ptr,
- always_create);
+ if (IsHost ())
+ return ModuleList::GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr,
+ false);
+
+ return GetRemoteSharedModule (module_spec,
+ process,
+ module_sp,
+ [&](const ModuleSpec &spec)
+ {
+ return ModuleList::GetSharedModule (
+ spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr, false);
+ },
+ did_create_ptr);
+}
+
+bool
+Platform::GetModuleSpec (const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec)
+{
+ ModuleSpecList module_specs;
+ if (ObjectFile::GetModuleSpecifications (module_file_spec, 0, 0, module_specs) == 0)
+ return false;
+
+ ModuleSpec matched_module_spec;
+ return module_specs.FindMatchingModuleSpec (ModuleSpec (module_file_spec, arch),
+ module_spec);
}
PlatformSP
@@ -298,7 +431,8 @@ 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_module_cache (llvm::make_unique<ModuleCache> ())
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
@@ -476,16 +610,16 @@ Platform::AddClangModuleCompilationOptions (Target *target, std::vector<std::str
}
-ConstString
+FileSpec
Platform::GetWorkingDirectory ()
{
if (IsHost())
{
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)))
- return ConstString(cwd);
+ return FileSpec{cwd, true};
else
- return ConstString();
+ return FileSpec{};
}
else
{
@@ -524,11 +658,11 @@ RecurseCopy_Callback (void *baton,
FileSpec dst_dir = rc_baton->dst;
if (!dst_dir.GetFilename())
dst_dir.GetFilename() = src.GetLastPathComponent();
- std::string dst_dir_path (dst_dir.GetPath());
- Error error = rc_baton->platform_ptr->MakeDirectory(dst_dir_path.c_str(), lldb::eFilePermissionsDirectoryDefault);
+ Error error = rc_baton->platform_ptr->MakeDirectory(dst_dir, lldb::eFilePermissionsDirectoryDefault);
if (error.Fail())
{
- rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end", dst_dir_path.c_str());
+ rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end",
+ dst_dir.GetCString());
return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
}
@@ -556,15 +690,15 @@ RecurseCopy_Callback (void *baton,
FileSpec dst_file = rc_baton->dst;
if (!dst_file.GetFilename())
dst_file.GetFilename() = src.GetFilename();
-
- char buf[PATH_MAX];
- rc_baton->error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf));
+ FileSpec src_resolved;
+
+ rc_baton->error = FileSystem::Readlink(src, src_resolved);
if (rc_baton->error.Fail())
return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
-
- rc_baton->error = rc_baton->platform_ptr->CreateSymlink(dst_file.GetPath().c_str(), buf);
+
+ rc_baton->error = rc_baton->platform_ptr->CreateSymlink(dst_file, src_resolved);
if (rc_baton->error.Fail())
return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
@@ -611,7 +745,7 @@ Platform::Install (const FileSpec& src, const FileSpec& dst)
if (!fixed_dst.GetFilename())
fixed_dst.GetFilename() = src.GetFilename();
- ConstString working_dir = GetWorkingDirectory();
+ FileSpec working_dir = GetWorkingDirectory();
if (dst)
{
@@ -631,8 +765,8 @@ Platform::Install (const FileSpec& src, const FileSpec& dst)
std::string path;
if (working_dir)
{
- relative_spec.SetFile(working_dir.GetCString(), false);
- relative_spec.AppendPathComponent(dst.GetPath().c_str());
+ relative_spec = working_dir;
+ relative_spec.AppendPathComponent(dst.GetPath());
fixed_dst.GetDirectory() = relative_spec.GetDirectory();
}
else
@@ -646,7 +780,7 @@ Platform::Install (const FileSpec& src, const FileSpec& dst)
{
if (working_dir)
{
- fixed_dst.GetDirectory() = working_dir;
+ fixed_dst.GetDirectory().SetCString(working_dir.GetCString());
}
else
{
@@ -659,7 +793,7 @@ Platform::Install (const FileSpec& src, const FileSpec& dst)
{
if (working_dir)
{
- fixed_dst.GetDirectory() = working_dir;
+ fixed_dst.GetDirectory().SetCString(working_dir.GetCString());
}
else
{
@@ -682,18 +816,17 @@ Platform::Install (const FileSpec& src, const FileSpec& dst)
case FileSpec::eFileTypeDirectory:
{
if (GetFileExists (fixed_dst))
- Unlink (fixed_dst.GetPath().c_str());
+ Unlink(fixed_dst);
uint32_t permissions = src.GetPermissions();
if (permissions == 0)
permissions = eFilePermissionsDirectoryDefault;
- std::string dst_dir_path(fixed_dst.GetPath());
- error = MakeDirectory(dst_dir_path.c_str(), permissions);
+ error = MakeDirectory(fixed_dst, permissions);
if (error.Success())
{
// Make a filespec that only fills in the directory of a FileSpec so
// when we enumerate we can quickly fill in the filename for dst copies
FileSpec recurse_dst;
- recurse_dst.GetDirectory().SetCString(dst_dir_path.c_str());
+ recurse_dst.GetDirectory().SetCString(fixed_dst.GetCString());
std::string src_dir_path (src.GetPath());
RecurseCopyBaton baton = { recurse_dst, this, Error() };
FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &baton);
@@ -704,18 +837,18 @@ Platform::Install (const FileSpec& src, const FileSpec& dst)
case FileSpec::eFileTypeRegular:
if (GetFileExists (fixed_dst))
- Unlink (fixed_dst.GetPath().c_str());
+ Unlink(fixed_dst);
error = PutFile(src, fixed_dst);
break;
case FileSpec::eFileTypeSymbolicLink:
{
if (GetFileExists (fixed_dst))
- Unlink (fixed_dst.GetPath().c_str());
- char buf[PATH_MAX];
- error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf));
+ Unlink(fixed_dst);
+ FileSpec src_resolved;
+ error = FileSystem::Readlink(src, src_resolved);
if (error.Success())
- error = CreateSymlink(dst.GetPath().c_str(), buf);
+ error = CreateSymlink(dst, src_resolved);
}
break;
case FileSpec::eFileTypePipe:
@@ -735,37 +868,33 @@ Platform::Install (const FileSpec& src, const FileSpec& dst)
}
bool
-Platform::SetWorkingDirectory (const ConstString &path)
+Platform::SetWorkingDirectory(const FileSpec &file_spec)
{
if (IsHost())
{
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
- log->Printf("Platform::SetWorkingDirectory('%s')", path.GetCString());
-#ifdef _WIN32
- // Not implemented on Windows
- return false;
-#else
- if (path)
+ log->Printf("Platform::SetWorkingDirectory('%s')",
+ file_spec.GetCString());
+ if (file_spec)
{
- if (chdir(path.GetCString()) == 0)
+ if (::chdir(file_spec.GetCString()) == 0)
return true;
}
return false;
-#endif
}
else
{
m_working_dir.Clear();
- return SetRemoteWorkingDirectory(path);
+ return SetRemoteWorkingDirectory(file_spec);
}
}
Error
-Platform::MakeDirectory (const char *path, uint32_t permissions)
+Platform::MakeDirectory(const FileSpec &file_spec, uint32_t permissions)
{
if (IsHost())
- return FileSystem::MakeDirectory(path, permissions);
+ return FileSystem::MakeDirectory(file_spec, permissions);
else
{
Error error;
@@ -775,10 +904,10 @@ Platform::MakeDirectory (const char *path, uint32_t permissions)
}
Error
-Platform::GetFilePermissions (const char *path, uint32_t &file_permissions)
+Platform::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions)
{
if (IsHost())
- return FileSystem::GetFilePermissions(path, file_permissions);
+ return FileSystem::GetFilePermissions(file_spec, file_permissions);
else
{
Error error;
@@ -788,10 +917,10 @@ Platform::GetFilePermissions (const char *path, uint32_t &file_permissions)
}
Error
-Platform::SetFilePermissions (const char *path, uint32_t file_permissions)
+Platform::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions)
{
if (IsHost())
- return FileSystem::SetFilePermissions(path, file_permissions);
+ return FileSystem::SetFilePermissions(file_spec, file_permissions);
else
{
Error error;
@@ -818,12 +947,13 @@ Platform::GetHostname ()
}
bool
-Platform::SetRemoteWorkingDirectory(const ConstString &path)
+Platform::SetRemoteWorkingDirectory(const FileSpec &working_dir)
{
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
- log->Printf("Platform::SetRemoteWorkingDirectory('%s')", path.GetCString());
- m_working_dir = path;
+ log->Printf("Platform::SetRemoteWorkingDirectory('%s')",
+ working_dir.GetCString());
+ m_working_dir = working_dir;
return true;
}
@@ -1092,6 +1222,12 @@ Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
num_resumes))
return error;
}
+ else if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
+ {
+ error = ShellExpandArguments(launch_info);
+ if (error.Fail())
+ return error;
+ }
if (log)
log->Printf ("Platform::%s final launch_info resume count: %" PRIu32, __FUNCTION__, launch_info.GetResumeCount ());
@@ -1104,16 +1240,41 @@ Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
}
Error
+Platform::ShellExpandArguments (ProcessLaunchInfo &launch_info)
+{
+ if (IsHost())
+ return Host::ShellExpandArguments(launch_info);
+ return Error("base lldb_private::Platform class can't expand arguments");
+}
+
+Error
Platform::KillProcess (const lldb::pid_t pid)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
if (log)
log->Printf ("Platform::%s, pid %" PRIu64, __FUNCTION__, pid);
- if (!IsHost ())
- return Error ("base lldb_private::Platform class can't launch remote processes");
+ // Try to find a process plugin to handle this Kill request. If we can't, fall back to
+ // the default OS implementation.
+ size_t num_debuggers = Debugger::GetNumDebuggers();
+ for (size_t didx = 0; didx < num_debuggers; ++didx)
+ {
+ DebuggerSP debugger = Debugger::GetDebuggerAtIndex(didx);
+ lldb_private::TargetList &targets = debugger->GetTargetList();
+ for (int tidx = 0; tidx < targets.GetNumTargets(); ++tidx)
+ {
+ ProcessSP process = targets.GetTargetAtIndex(tidx)->GetProcessSP();
+ if (process->GetID() == pid)
+ return process->Destroy(true);
+ }
+ }
- Host::Kill (pid, SIGTERM);
+ if (!IsHost())
+ {
+ return Error("base lldb_private::Platform class can't kill remote processes unless "
+ "they are controlled by a process plugin");
+ }
+ Host::Kill(pid, SIGTERM);
return Error();
}
@@ -1251,7 +1412,7 @@ Platform::PutFile (const FileSpec& source,
if (log)
log->Printf("[PutFile] Using block by block transfer....\n");
- uint32_t source_open_options = File::eOpenOptionRead;
+ uint32_t source_open_options = File::eOpenOptionRead | File::eOpenOptionCloseOnExec;
if (source.GetFileType() == FileSpec::eFileTypeSymbolicLink)
source_open_options |= File::eOpenoptionDontFollowSymlinks;
@@ -1266,7 +1427,8 @@ Platform::PutFile (const FileSpec& source,
lldb::user_id_t dest_file = OpenFile (destination,
File::eOpenOptionCanCreate |
File::eOpenOptionWrite |
- File::eOpenOptionTruncate,
+ File::eOpenOptionTruncate |
+ File::eOpenOptionCloseOnExec,
permissions,
error);
if (log)
@@ -1309,43 +1471,52 @@ Platform::PutFile (const FileSpec& source,
}
Error
-Platform::GetFile (const FileSpec& source,
- const FileSpec& destination)
+Platform::GetFile(const FileSpec &source,
+ const FileSpec &destination)
{
Error error("unimplemented");
return error;
}
Error
-Platform::CreateSymlink (const char *src, // The name of the link is in src
- const char *dst)// The symlink points to dst
+Platform::CreateSymlink(const FileSpec &src, // The name of the link is in src
+ const FileSpec &dst) // The symlink points to dst
{
Error error("unimplemented");
return error;
}
bool
-Platform::GetFileExists (const lldb_private::FileSpec& file_spec)
+Platform::GetFileExists(const lldb_private::FileSpec &file_spec)
{
return false;
}
Error
-Platform::Unlink (const char *path)
+Platform::Unlink(const FileSpec &path)
{
Error error("unimplemented");
return error;
}
-
+uint64_t
+Platform::ConvertMmapFlagsToPlatform(const ArchSpec &arch, unsigned flags)
+{
+ uint64_t flags_platform = 0;
+ if (flags & eMmapFlagsPrivate)
+ flags_platform |= MAP_PRIVATE;
+ if (flags & eMmapFlagsAnon)
+ flags_platform |= MAP_ANON;
+ return flags_platform;
+}
lldb_private::Error
-Platform::RunShellCommand (const char *command, // Shouldn't be NULL
- const char *working_dir, // Pass NULL to use the current working directory
- int *status_ptr, // Pass NULL if you don't want the process exit status
- int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
- std::string *command_output, // Pass NULL if you don't want the command output
- uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
+Platform::RunShellCommand(const char *command, // Shouldn't be NULL
+ const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
{
if (IsHost())
return Host::RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
@@ -1609,3 +1780,174 @@ Platform::GetTrapHandlerSymbolNames ()
return m_trap_handlers;
}
+Error
+Platform::GetCachedExecutable (ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ Platform &remote_platform)
+{
+ const auto platform_spec = module_spec.GetFileSpec ();
+ const auto error = LoadCachedExecutable (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ remote_platform);
+ if (error.Success ())
+ {
+ module_spec.GetFileSpec () = module_sp->GetFileSpec ();
+ module_spec.GetPlatformFileSpec () = platform_spec;
+ }
+
+ return error;
+}
+
+Error
+Platform::LoadCachedExecutable (const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ Platform &remote_platform)
+{
+ return GetRemoteSharedModule (module_spec,
+ nullptr,
+ module_sp,
+ [&](const ModuleSpec &spec)
+ {
+ return remote_platform.ResolveExecutable (
+ spec, module_sp, module_search_paths_ptr);
+ },
+ nullptr);
+}
+
+Error
+Platform::GetRemoteSharedModule (const ModuleSpec &module_spec,
+ Process* process,
+ lldb::ModuleSP &module_sp,
+ const ModuleResolver &module_resolver,
+ bool *did_create_ptr)
+{
+ // Get module information from a target.
+ ModuleSpec resolved_module_spec;
+ bool got_module_spec = false;
+ if (process)
+ {
+ // Try to get module information from the process
+ if (process->GetModuleSpec (module_spec.GetFileSpec (), module_spec.GetArchitecture (), resolved_module_spec))
+ got_module_spec = true;
+ }
+
+ if (!got_module_spec)
+ {
+ // Get module information from a target.
+ if (!GetModuleSpec (module_spec.GetFileSpec (), module_spec.GetArchitecture (), resolved_module_spec))
+ return module_resolver (module_spec);
+ }
+
+ // Trying to find a module by UUID on local file system.
+ const auto error = module_resolver (resolved_module_spec);
+ if (error.Fail ())
+ {
+ if (GetCachedSharedModule (resolved_module_spec, module_sp, did_create_ptr))
+ return Error ();
+ }
+
+ return error;
+}
+
+bool
+Platform::GetCachedSharedModule (const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ bool *did_create_ptr)
+{
+ if (IsHost() ||
+ !GetGlobalPlatformProperties ()->GetUseModuleCache ())
+ return false;
+
+ Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM);
+
+ // Check local cache for a module.
+ auto error = m_module_cache->GetAndPut (
+ GetModuleCacheRoot (),
+ GetCacheHostname (),
+ module_spec,
+ [=](const ModuleSpec &module_spec, const FileSpec &tmp_download_file_spec)
+ {
+ return DownloadModuleSlice (module_spec.GetFileSpec (),
+ module_spec.GetObjectOffset (),
+ module_spec.GetObjectSize (),
+ tmp_download_file_spec);
+
+ },
+ module_sp,
+ did_create_ptr);
+ if (error.Success ())
+ return true;
+
+ if (log)
+ log->Printf("Platform::%s - module %s not found in local cache: %s",
+ __FUNCTION__, module_spec.GetUUID ().GetAsString ().c_str (), error.AsCString ());
+ return false;
+}
+
+Error
+Platform::DownloadModuleSlice (const FileSpec& src_file_spec,
+ const uint64_t src_offset,
+ const uint64_t src_size,
+ const FileSpec& dst_file_spec)
+{
+ Error error;
+
+ std::ofstream dst (dst_file_spec.GetPath(), std::ios::out | std::ios::binary);
+ if (!dst.is_open())
+ {
+ error.SetErrorStringWithFormat ("unable to open destination file: %s", dst_file_spec.GetPath ().c_str ());
+ return error;
+ }
+
+ auto src_fd = OpenFile (src_file_spec,
+ File::eOpenOptionRead,
+ lldb::eFilePermissionsFileDefault,
+ error);
+
+ if (error.Fail ())
+ {
+ error.SetErrorStringWithFormat ("unable to open source file: %s", error.AsCString ());
+ return error;
+ }
+
+ std::vector<char> buffer (1024);
+ auto offset = src_offset;
+ uint64_t total_bytes_read = 0;
+ while (total_bytes_read < src_size)
+ {
+ const auto to_read = std::min (static_cast<uint64_t>(buffer.size ()), src_size - total_bytes_read);
+ const uint64_t n_read = ReadFile (src_fd, offset, &buffer[0], to_read, error);
+ if (error.Fail ())
+ break;
+ if (n_read == 0)
+ {
+ error.SetErrorString ("read 0 bytes");
+ break;
+ }
+ offset += n_read;
+ total_bytes_read += n_read;
+ dst.write (&buffer[0], n_read);
+ }
+
+ Error close_error;
+ CloseFile (src_fd, close_error); // Ignoring close error.
+
+ return error;
+}
+
+FileSpec
+Platform::GetModuleCacheRoot ()
+{
+ auto dir_spec = GetGlobalPlatformProperties ()->GetModuleCacheDirectory ();
+ dir_spec.AppendPathComponent (GetName ().AsCString ());
+ return dir_spec;
+}
+
+const char *
+Platform::GetCacheHostname ()
+{
+ return GetHostname ();
+}
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index f7a26f676aba..41942829ca55 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -7,22 +7,19 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Target/Process.h"
-
-#include "lldb/lldb-private-log.h"
-
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
@@ -30,11 +27,15 @@
#include "lldb/Host/Terminal.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/InstrumentationRuntime.h"
#include "lldb/Target/JITLoader.h"
+#include "lldb/Target/JITLoaderList.h"
#include "lldb/Target/MemoryHistory.h"
+#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/OperatingSystem.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/CPPLanguageRuntime.h"
@@ -48,7 +49,8 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanBase.h"
-#include "lldb/Target/InstrumentationRuntime.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/NameMatches.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
using namespace lldb;
@@ -430,7 +432,7 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
case 'i': // STDIN for read only
{
FileAction action;
- if (action.Open (STDIN_FILENO, option_arg, true, false))
+ if (action.Open(STDIN_FILENO, FileSpec{option_arg, false}, true, false))
launch_info.AppendFileAction (action);
break;
}
@@ -438,7 +440,7 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
case 'o': // Open STDOUT for write only
{
FileAction action;
- if (action.Open (STDOUT_FILENO, option_arg, false, true))
+ if (action.Open(STDOUT_FILENO, FileSpec{option_arg, false}, false, true))
launch_info.AppendFileAction (action);
break;
}
@@ -446,7 +448,7 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
case 'e': // STDERR for write only
{
FileAction action;
- if (action.Open (STDERR_FILENO, option_arg, false, true))
+ if (action.Open(STDERR_FILENO, FileSpec{option_arg, false}, false, true))
launch_info.AppendFileAction (action);
break;
}
@@ -458,17 +460,18 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
case 'n': // Disable STDIO
{
FileAction action;
- if (action.Open (STDIN_FILENO, "/dev/null", true, false))
+ const FileSpec dev_null{"/dev/null", false};
+ if (action.Open(STDIN_FILENO, dev_null, true, false))
launch_info.AppendFileAction (action);
- if (action.Open (STDOUT_FILENO, "/dev/null", false, true))
+ if (action.Open(STDOUT_FILENO, dev_null, false, true))
launch_info.AppendFileAction (action);
- if (action.Open (STDERR_FILENO, "/dev/null", false, true))
+ if (action.Open(STDERR_FILENO, dev_null, false, true))
launch_info.AppendFileAction (action);
break;
}
case 'w':
- launch_info.SetWorkingDirectory (option_arg);
+ launch_info.SetWorkingDirectory(FileSpec{option_arg, false});
break;
case 't': // Open process in new terminal window
@@ -491,6 +494,17 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
break;
}
+ case 'X': // shell expand args.
+ {
+ bool success;
+ const bool expand_args = Args::StringToBoolean (option_arg, true, &success);
+ if (success)
+ launch_info.SetShellExpandArguments(expand_args);
+ else
+ error.SetErrorStringWithFormat ("Invalid boolean value for shell-expand-args option: '%s'", option_arg ? option_arg : "<null>");
+ break;
+ }
+
case 'c':
if (option_arg && option_arg[0])
launch_info.SetShell (FileSpec(option_arg, false));
@@ -518,7 +532,7 @@ ProcessLaunchCommandOptions::g_option_table[] =
{ 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|LLDB_OPT_SET_2|LLDB_OPT_SET_3, 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, 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>."},
@@ -527,7 +541,7 @@ ProcessLaunchCommandOptions::g_option_table[] =
{ 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, NULL, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process."},
-
+{ LLDB_OPT_SET_4, false, "shell-expand-args", 'X', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Set whether to shell expand arguments to the process when launching."},
{ 0 , false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -688,7 +702,7 @@ Process::Process(Target &target, Listener &listener) :
Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_signals_sp) :
ProcessProperties (this),
UserID (LLDB_INVALID_PROCESS_ID),
- Broadcaster (&(target.GetDebugger()), "lldb.process"),
+ Broadcaster (&(target.GetDebugger()), Process::GetStaticBroadcasterClass().AsCString()),
m_target (target),
m_public_state (eStateUnloaded),
m_private_state (eStateUnloaded),
@@ -720,12 +734,12 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
m_process_input_reader (),
m_stdio_communication ("process.stdio"),
m_stdio_communication_mutex (Mutex::eMutexTypeRecursive),
- m_stdio_disable(true),
+ m_stdin_forward (false),
m_stdout_data (),
m_stderr_data (),
m_profile_data_comm_mutex (Mutex::eMutexTypeRecursive),
m_profile_data (),
- m_iohandler_sync (false),
+ m_iohandler_sync (0),
m_memory_cache (*this),
m_allocated_memory_cache (*this),
m_should_detach (false),
@@ -734,9 +748,10 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
m_private_run_lock (),
m_currently_handling_event(false),
m_stop_info_override_callback (NULL),
- m_finalize_called(false),
+ m_finalizing (false),
+ m_finalize_called (false),
m_clear_thread_plans_on_stop (false),
- m_force_next_event_delivery(false),
+ m_force_next_event_delivery (false),
m_last_broadcast_state (eStateInvalid),
m_destroy_in_process (false),
m_can_jit(eCanJITDontKnow)
@@ -807,6 +822,9 @@ Process::GetGlobalProperties()
void
Process::Finalize()
{
+ m_finalizing = true;
+
+ // Destroy this process if needed
switch (GetPrivateState())
{
case eStateConnected:
@@ -817,14 +835,7 @@ Process::Finalize()
case eStateStepping:
case eStateCrashed:
case eStateSuspended:
- if (GetShouldDetach())
- {
- // FIXME: This will have to be a process setting:
- bool keep_stopped = false;
- Detach(keep_stopped);
- }
- else
- Destroy();
+ Destroy(false);
break;
case eStateInvalid:
@@ -862,6 +873,9 @@ Process::Finalize()
m_instrumentation_runtimes.clear();
m_next_event_action_ap.reset();
m_stop_info_override_callback = NULL;
+ // Clear the last natural stop ID since it has a strong
+ // reference to this process
+ m_mod_id.SetStopEventForLastNaturalStopID(EventSP());
//#ifdef LLDB_CONFIGURATION_DEBUG
// StreamFile s(stdout, false);
// EventSP event_sp;
@@ -937,33 +951,21 @@ Process::GetNextEvent (EventSP &event_sp)
return state;
}
-bool
-Process::SyncIOHandler (uint64_t timeout_msec)
+void
+Process::SyncIOHandler (uint32_t iohandler_id, 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 ());
- }
+ if (! m_process_input_reader)
+ return;
- // reset sync one-shot so it will be ready for next launch
- m_iohandler_sync.SetValue(false, eBroadcastNever);
- }
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithMicroSeconds(timeout_msec*1000);
+ uint32_t new_iohandler_id = 0;
+ m_iohandler_sync.WaitForValueNotEqualTo(iohandler_id, new_iohandler_id, &timeout);
- return !timed_out;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::%s waited for m_iohandler_sync to change from %u, new value is %u", __FUNCTION__, iohandler_id, new_iohandler_id);
}
StateType
@@ -991,10 +993,15 @@ Process::WaitForProcessToStop (const TimeValue *timeout,
if (!wait_always &&
StateIsStoppedState(state, true) &&
- StateIsStoppedState(GetPrivateState(), true)) {
+ StateIsStoppedState(GetPrivateState(), true))
+ {
if (log)
log->Printf("Process::%s returning without waiting for events; process private and public states are already 'stopped'.",
__FUNCTION__);
+ // We need to toggle the run lock as this won't get done in
+ // SetPublicState() if the process is hijacked.
+ if (hijack_listener)
+ m_public_run_lock.SetStopped();
return state;
}
@@ -1422,6 +1429,9 @@ Process::GetExitDescription ()
bool
Process::SetExitStatus (int status, const char *cstr)
{
+ // Use a mutex to protect setting the exit status.
+ Mutex::Locker locker (m_exit_status_mutex);
+
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
if (log)
log->Printf("Process::SetExitStatus (status=%i (0x%8.8x), description=%s%s%s)",
@@ -1437,21 +1447,35 @@ Process::SetExitStatus (int status, const char *cstr)
log->Printf("Process::SetExitStatus () ignoring exit status because state was already set to eStateExited");
return false;
}
-
- // use a mutex to protect the status and string during updating
- {
- Mutex::Locker locker (m_exit_status_mutex);
- m_exit_status = status;
- if (cstr)
- m_exit_string = cstr;
- else
- m_exit_string.clear();
+ m_exit_status = status;
+ if (cstr)
+ m_exit_string = cstr;
+ else
+ m_exit_string.clear();
+
+ // When we exit, we no longer need to the communication channel
+ m_stdio_communication.Disconnect();
+ m_stdio_communication.StopReadThread();
+ m_stdin_forward = false;
+
+ // And we don't need the input reader anymore as well
+ if (m_process_input_reader)
+ {
+ m_process_input_reader->SetIsDone(true);
+ m_process_input_reader->Cancel();
+ m_process_input_reader.reset();
}
- DidExit ();
+ // Clear the last natural stop ID since it has a strong
+ // reference to this process
+ m_mod_id.SetStopEventForLastNaturalStopID(EventSP());
SetPrivateState (eStateExited);
+
+ // Allow subclasses to do some cleanup
+ DidExit ();
+
return true;
}
@@ -1531,10 +1555,24 @@ Process::UpdateThreadListIfNeeded ()
for (size_t i=0; i<num_old_threads; ++i)
old_thread_list.GetThreadAtIndex(i, false)->ClearBackingThread();
+ // Turn off dynamic types to ensure we don't run any expressions. Objective C
+ // can run an expression to determine if a SBValue is a dynamic type or not
+ // and we need to avoid this. OperatingSystem plug-ins can't run expressions
+ // that require running code...
+
+ Target &target = GetTarget();
+ const lldb::DynamicValueType saved_prefer_dynamic = target.GetPreferDynamicValue ();
+ if (saved_prefer_dynamic != lldb::eNoDynamicValues)
+ target.SetPreferDynamicValue(lldb::eNoDynamicValues);
+
// Now let the OperatingSystem plug-in update the thread list
+
os->UpdateThreadList (old_thread_list, // Old list full of threads created by OS plug-in
real_thread_list, // The actual thread list full of threads created by each lldb_private::Process subclass
new_thread_list); // The new thread list that we will show to the user that gets filled in
+
+ if (saved_prefer_dynamic != lldb::eNoDynamicValues)
+ target.SetPreferDynamicValue(saved_prefer_dynamic);
}
else
{
@@ -1714,15 +1752,17 @@ Process::ResumeSynchronous (Stream *stream)
HijackProcessEvents(listener_sp.get());
Error error = PrivateResume();
-
- StateType state = WaitForProcessToStop (NULL, NULL, true, listener_sp.get(), stream);
+ if (error.Success())
+ {
+ StateType state = WaitForProcessToStop (NULL, NULL, true, listener_sp.get(), stream);
+ const bool must_be_alive = false; // eStateExited is ok, so this must be false
+ if (!StateIsStoppedState(state, must_be_alive))
+ error.SetErrorStringWithFormat("process not in stopped state after synchronous resume: %s", StateAsCString(state));
+ }
// Undo the hijacking of process events...
RestoreProcessEvents();
- if (error.Success() && !StateIsStoppedState(state, false))
- error.SetErrorStringWithFormat("process not in stopped state after synchronous resume: %s", StateAsCString(state));
-
return error;
}
@@ -1763,6 +1803,7 @@ Process::SetPrivateState (StateType new_state)
if (state_changed)
{
m_private_state.SetValueNoLock (new_state);
+ EventSP event_sp (new Event (eBroadcastBitStateChanged, new ProcessEventData (shared_from_this(), new_state)));
if (StateIsStoppedState(new_state, false))
{
// Note, this currently assumes that all threads in the list
@@ -1779,15 +1820,18 @@ Process::SetPrivateState (StateType new_state)
m_thread_list.DidStop();
m_mod_id.BumpStopID();
+ if (!m_mod_id.IsLastResumeForUserExpression())
+ m_mod_id.SetStopEventForLastNaturalStopID(event_sp);
m_memory_cache.Clear();
if (log)
log->Printf("Process::SetPrivateState (%s) stop_id = %u", StateAsCString(new_state), m_mod_id.GetStopID());
}
+
// Use our target to get a shared pointer to ourselves...
if (m_finalize_called && PrivateStateThreadIsValid() == false)
- BroadcastEvent (eBroadcastBitStateChanged, new ProcessEventData (shared_from_this(), new_state));
+ BroadcastEvent (event_sp);
else
- m_private_state_broadcaster.BroadcastEvent (eBroadcastBitStateChanged, new ProcessEventData (shared_from_this(), new_state));
+ m_private_state_broadcaster.BroadcastEvent (event_sp);
}
else
{
@@ -1819,6 +1863,12 @@ Process::GetImageInfoAddress()
uint32_t
Process::LoadImage (const FileSpec &image_spec, Error &error)
{
+ if (m_finalizing)
+ {
+ error.SetErrorString("process is tearing itself down");
+ return LLDB_INVALID_IMAGE_TOKEN;
+ }
+
char path[PATH_MAX];
image_spec.GetPath(path, sizeof(path));
@@ -1938,6 +1988,13 @@ Error
Process::UnloadImage (uint32_t image_token)
{
Error error;
+
+ if (m_finalizing)
+ {
+ error.SetErrorString("process is tearing itself down");
+ return error;
+ }
+
if (image_token < m_image_tokens.size())
{
const addr_t image_addr = m_image_tokens[image_token];
@@ -2020,6 +2077,9 @@ Process::GetABI()
LanguageRuntime *
Process::GetLanguageRuntime(lldb::LanguageType language, bool retry_if_null)
{
+ if (m_finalizing)
+ return nullptr;
+
LanguageRuntimeCollection::iterator pos;
pos = m_language_runtimes.find (language);
if (pos == m_language_runtimes.end() || (retry_if_null && !(*pos).second))
@@ -2054,6 +2114,9 @@ Process::GetObjCLanguageRuntime (bool retry_if_null)
bool
Process::IsPossibleDynamicValue (ValueObject& in_value)
{
+ if (m_finalizing)
+ return false;
+
if (in_value.IsDynamic())
return false;
LanguageType known_type = in_value.GetObjectRuntimeLanguage();
@@ -2072,6 +2135,12 @@ Process::IsPossibleDynamicValue (ValueObject& in_value)
return objc_runtime ? objc_runtime->CouldHaveDynamicValue(in_value) : false;
}
+void
+Process::SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers)
+{
+ m_dynamic_checkers_ap.reset(dynamic_checkers);
+}
+
BreakpointSiteList &
Process::GetBreakpointSiteList()
{
@@ -2177,11 +2246,12 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw
if (symbol && symbol->IsIndirect())
{
Error error;
- load_addr = ResolveIndirectFunction (&symbol->GetAddress(), error);
+ Address symbol_address = symbol->GetAddress();
+ load_addr = ResolveIndirectFunction (&symbol_address, error);
if (!error.Success() && show_error)
{
m_target.GetDebugger().GetErrorFile()->Printf ("warning: failed to resolve indirect function at 0x%" PRIx64 " for breakpoint %i.%i: %s\n",
- symbol->GetAddress().GetLoadAddress(&m_target),
+ symbol->GetLoadAddress(&m_target),
owner->GetBreakpoint().GetID(),
owner->GetID(),
error.AsCString() ? error.AsCString() : "unknown error");
@@ -2403,7 +2473,7 @@ Process::DisableSoftwareBreakpoint (BreakpointSite *bp_site)
if (DoReadMemory (bp_addr, curr_break_op, break_op_size, error) == break_op_size)
{
bool verify = false;
- // Make sure we have the a breakpoint opcode exists at this address
+ // Make sure the breakpoint opcode exists at this address
if (::memcmp (curr_break_op, break_op, break_op_size) == 0)
{
break_op_found = true;
@@ -2968,6 +3038,33 @@ Process::ReadModuleFromMemory (const FileSpec& file_spec,
return ModuleSP();
}
+bool
+Process::GetLoadAddressPermissions (lldb::addr_t load_addr, uint32_t &permissions)
+{
+ MemoryRegionInfo range_info;
+ permissions = 0;
+ Error error (GetMemoryRegionInfo (load_addr, range_info));
+ if (!error.Success())
+ return false;
+ if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow
+ || range_info.GetWritable() == MemoryRegionInfo::eDontKnow
+ || range_info.GetExecutable() == MemoryRegionInfo::eDontKnow)
+ {
+ return false;
+ }
+
+ if (range_info.GetReadable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsReadable;
+
+ if (range_info.GetWritable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsWritable;
+
+ if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsExecutable;
+
+ return true;
+}
+
Error
Process::EnableWatchpoint (Watchpoint *watchpoint, bool notify)
{
@@ -3090,8 +3187,9 @@ Process::Launch (ProcessLaunchInfo &launch_info)
{
// We were able to launch the process, but we failed to
// catch the initial stop.
+ error.SetErrorString ("failed to catch stop after launch");
SetExitStatus (0, "failed to catch stop after launch");
- Destroy();
+ Destroy(false);
}
else if (state == eStateStopped || state == eStateCrashed)
{
@@ -3125,7 +3223,7 @@ Process::Launch (ProcessLaunchInfo &launch_info)
// Target was stopped at entry as was intended. Need to notify the listeners
// about it.
- if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == true)
+ if (state == eStateStopped && launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))
HandlePrivateEvent(event_sp);
}
else if (state == eStateExited)
@@ -3152,6 +3250,9 @@ Process::LoadCore ()
Error error = DoLoadCore();
if (error.Success())
{
+ Listener listener ("lldb.process.load_core_listener");
+ HijackProcessEvents(&listener);
+
if (PrivateStateThreadIsValid ())
ResumePrivateStateThread ();
else
@@ -3172,7 +3273,20 @@ Process::LoadCore ()
// show all of the threads in the core file and explore the crashed
// state.
SetPrivateState (eStateStopped);
-
+
+ // Wait indefinitely for a stopped event since we just posted one above...
+ lldb::EventSP event_sp;
+ listener.WaitForEvent (NULL, event_sp);
+ StateType state = ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ if (!StateIsStoppedState (state, false))
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::Halt() failed to stop, state is: %s", StateAsCString(state));
+ error.SetErrorString ("Did not get stopped event after loading the core file.");
+ }
+ RestoreProcessEvents ();
}
return error;
}
@@ -3230,6 +3344,9 @@ Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)
switch (state)
{
+ case eStateAttaching:
+ return eEventActionSuccess;
+
case eStateRunning:
case eStateConnected:
return eEventActionRetry;
@@ -3702,7 +3819,7 @@ Process::Halt (bool clear_thread_plans)
RestorePrivateProcessEvents();
restored_process_events = true;
SetExitStatus(SIGKILL, "Cancelled async attach.");
- Destroy ();
+ Destroy (false);
}
else
{
@@ -3876,13 +3993,23 @@ Process::Detach (bool keep_stopped)
}
Error
-Process::Destroy ()
+Process::Destroy (bool force_kill)
{
// Tell ourselves we are in the process of destroying the process, so that we don't do any unnecessary work
// that might hinder the destruction. Remember to set this back to false when we are done. That way if the attempt
// failed and the process stays around for some reason it won't be in a confused state.
+
+ if (force_kill)
+ m_should_detach = false;
+ if (GetShouldDetach())
+ {
+ // FIXME: This will have to be a process setting:
+ bool keep_stopped = false;
+ Detach(keep_stopped);
+ }
+
m_destroy_in_process = true;
Error error (WillDestroy());
@@ -3910,9 +4037,9 @@ Process::Destroy ()
DidDestroy();
StopPrivateStateThread();
}
- m_stdio_communication.StopReadThread();
m_stdio_communication.Disconnect();
- m_stdio_disable = true;
+ m_stdio_communication.StopReadThread();
+ m_stdin_forward = false;
if (m_process_input_reader)
{
@@ -3954,6 +4081,20 @@ Process::Signal (int signal)
return error;
}
+void
+Process::SetUnixSignals (const UnixSignalsSP &signals_sp)
+{
+ assert (signals_sp && "null signals_sp");
+ m_unix_signals_sp = signals_sp;
+}
+
+UnixSignals &
+Process::GetUnixSignals ()
+{
+ assert (m_unix_signals_sp && "null m_unix_signals_sp");
+ return *m_unix_signals_sp;
+}
+
lldb::ByteOrder
Process::GetByteOrder () const
{
@@ -3976,12 +4117,14 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
switch (state)
{
- case eStateConnected:
- case eStateAttaching:
- case eStateLaunching:
case eStateDetached:
case eStateExited:
case eStateUnloaded:
+ m_stdio_communication.SynchronizeWithReadThread();
+ // fall-through
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
// These events indicate changes in the state of the debugging session, always report them.
return_value = true;
break;
@@ -4041,6 +4184,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
// If we aren't going to stop, let the thread plans decide if we're going to report this event.
// If no thread has an opinion, we don't report it.
+ m_stdio_communication.SynchronizeWithReadThread();
RefreshStateAfterStop ();
if (ProcessEventData::GetInterruptedFromEvent (event_ptr))
{
@@ -4128,7 +4272,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
bool
-Process::StartPrivateStateThread (bool force)
+Process::StartPrivateStateThread (bool is_secondary_thread)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
@@ -4136,7 +4280,7 @@ Process::StartPrivateStateThread (bool force)
if (log)
log->Printf ("Process::%s()%s ", __FUNCTION__, already_running ? " already running" : " starting private state thread");
- if (!force && already_running)
+ if (!is_secondary_thread && already_running)
return true;
// Create a thread that watches our internal state and controls which
@@ -4160,7 +4304,8 @@ Process::StartPrivateStateThread (bool force)
}
// Create the private state thread, and start it running.
- m_private_state_thread = ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread, this, NULL);
+ PrivateStateThreadArgs args = {this, is_secondary_thread};
+ m_private_state_thread = ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread, (void *) &args, NULL);
if (m_private_state_thread.IsJoinable())
{
ResumePrivateStateThread();
@@ -4324,13 +4469,17 @@ Process::HandlePrivateEvent (EventSP &event_sp)
// Only push the input handler if we aren't fowarding events,
// as this means the curses GUI is in use...
// Or don't push it if we are launching since it will come up stopped.
- if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching)
+ if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching &&
+ new_state != eStateAttaching)
+ {
PushProcessIOHandler ();
- m_iohandler_sync.SetValue(true, eBroadcastAlways);
+ m_iohandler_sync.SetValue(m_iohandler_sync.GetValue()+1, eBroadcastAlways);
+ if (log)
+ log->Printf("Process::%s updated m_iohandler_sync to %d", __FUNCTION__, m_iohandler_sync.GetValue());
+ }
}
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
@@ -4386,13 +4535,13 @@ Process::HandlePrivateEvent (EventSP &event_sp)
thread_result_t
Process::PrivateStateThread (void *arg)
{
- Process *proc = static_cast<Process*> (arg);
- thread_result_t result = proc->RunPrivateStateThread();
+ PrivateStateThreadArgs *real_args = static_cast<PrivateStateThreadArgs *> (arg);
+ thread_result_t result = real_args->process->RunPrivateStateThread(real_args->is_secondary_thread);
return result;
}
thread_result_t
-Process::RunPrivateStateThread ()
+Process::RunPrivateStateThread (bool is_secondary_thread)
{
bool control_only = true;
m_private_state_control_wait.SetValue (false, eBroadcastNever);
@@ -4484,7 +4633,11 @@ Process::RunPrivateStateThread ()
log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...",
__FUNCTION__, static_cast<void*>(this), GetID());
- m_public_run_lock.SetStopped();
+ // If we are a secondary thread, then the primary thread we are working for will have already
+ // acquired the public_run_lock, and isn't done with what it was doing yet, so don't
+ // try to change it on the way out.
+ if (!is_secondary_thread)
+ m_public_run_lock.SetStopped();
m_private_state_control_wait.SetValue (true, eBroadcastAlways);
m_private_state_thread.Reset();
return NULL;
@@ -4496,7 +4649,7 @@ Process::RunPrivateStateThread ()
Process::ProcessEventData::ProcessEventData () :
EventData (),
- m_process_sp (),
+ m_process_wp (),
m_state (eStateInvalid),
m_restarted (false),
m_update_state (0),
@@ -4506,12 +4659,14 @@ Process::ProcessEventData::ProcessEventData () :
Process::ProcessEventData::ProcessEventData (const ProcessSP &process_sp, StateType state) :
EventData (),
- m_process_sp (process_sp),
+ m_process_wp (),
m_state (state),
m_restarted (false),
m_update_state (0),
m_interrupted (false)
{
+ if (process_sp)
+ m_process_wp = process_sp;
}
Process::ProcessEventData::~ProcessEventData()
@@ -4534,6 +4689,11 @@ Process::ProcessEventData::GetFlavor () const
void
Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
{
+ ProcessSP process_sp(m_process_wp.lock());
+
+ if (!process_sp)
+ return;
+
// This function gets called twice for each event, once when the event gets pulled
// off of the private process event queue, and then any number of times, first when it gets pulled off of
// the public event queue, then other times when we're pretending that this is where we stopped at the
@@ -4543,7 +4703,7 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
if (m_update_state != 1)
return;
- m_process_sp->SetPublicState (m_state, Process::ProcessEventData::GetRestartedFromEvent(event_ptr));
+ process_sp->SetPublicState (m_state, Process::ProcessEventData::GetRestartedFromEvent(event_ptr));
// 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
@@ -4554,7 +4714,7 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
// 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();
+ ThreadList &curr_thread_list = process_sp->GetThreadList();
uint32_t num_threads = curr_thread_list.GetSize();
uint32_t idx;
@@ -4584,7 +4744,7 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
for (idx = 0; idx < num_threads; ++idx)
{
- curr_thread_list = m_process_sp->GetThreadList();
+ curr_thread_list = process_sp->GetThreadList();
if (curr_thread_list.GetSize() != num_threads)
{
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
@@ -4647,14 +4807,14 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
SetRestarted(true);
// Use the public resume method here, since this is just
// extending a public resume.
- m_process_sp->PrivateResume();
+ process_sp->PrivateResume();
}
else
{
// If we didn't restart, run the Stop Hooks here:
// They might also restart the target, so watch for that.
- m_process_sp->GetTarget().RunStopHooks();
- if (m_process_sp->GetPrivateState() == eStateRunning)
+ process_sp->GetTarget().RunStopHooks();
+ if (process_sp->GetPrivateState() == eStateRunning)
SetRestarted(true);
}
}
@@ -4664,9 +4824,13 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
void
Process::ProcessEventData::Dump (Stream *s) const
{
- if (m_process_sp)
+ ProcessSP process_sp(m_process_wp.lock());
+
+ if (process_sp)
s->Printf(" process = %p (pid = %" PRIu64 "), ",
- static_cast<void*>(m_process_sp.get()), m_process_sp->GetID());
+ static_cast<void*>(process_sp.get()), process_sp->GetID());
+ else
+ s->PutCString(" process = NULL, ");
s->Printf("state = %s", StateAsCString(GetState()));
}
@@ -4946,6 +5110,7 @@ public:
m_write_file (write_fd, false),
m_pipe ()
{
+ m_pipe.CreateNew(false);
m_read_file.SetDescriptor(GetInputFD(), false);
}
@@ -4955,130 +5120,93 @@ public:
}
- bool
- OpenPipes ()
- {
- if (m_pipe.CanRead() && m_pipe.CanWrite())
- return true;
- Error result = m_pipe.CreateNew(false);
- return result.Success();
- }
-
- void
- ClosePipes()
- {
- m_pipe.Close();
- }
-
// Each IOHandler gets to run until it is done. It should read data
// from the "in" and place output into "out" and "err and return
// when done.
- virtual void
- Run ()
+ void
+ Run () override
{
- if (m_read_file.IsValid() && m_write_file.IsValid())
+ if (!m_read_file.IsValid() || !m_write_file.IsValid() || !m_pipe.CanRead() || !m_pipe.CanWrite())
{
- SetIsDone(false);
- if (OpenPipes())
- {
- const int read_fd = m_read_file.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);
+ SetIsDone(true);
+ return;
+ }
+
+ SetIsDone(false);
+ const int read_fd = m_read_file.GetDescriptor();
+ 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 _WIN32
- while (!GetIsDone())
+ const int pipe_read_fd = m_pipe.GetReadFileDescriptor();
+ while (!GetIsDone())
+ {
+ fd_set read_fdset;
+ FD_ZERO (&read_fdset);
+ FD_SET (read_fd, &read_fdset);
+ FD_SET (pipe_read_fd, &read_fdset);
+ const int nfds = std::max<int>(read_fd, pipe_read_fd) + 1;
+ int num_set_fds = select (nfds, &read_fdset, NULL, NULL, NULL);
+ if (num_set_fds < 0)
+ {
+ const int select_errno = errno;
+
+ if (select_errno != EINTR)
+ SetIsDone(true);
+ }
+ else if (num_set_fds > 0)
+ {
+ char ch = 0;
+ size_t n;
+ if (FD_ISSET (read_fd, &read_fdset))
{
- fd_set read_fdset;
- FD_ZERO (&read_fdset);
- FD_SET (read_fd, &read_fdset);
- FD_SET (pipe_read_fd, &read_fdset);
- const int nfds = std::max<int>(read_fd, pipe_read_fd) + 1;
- int num_set_fds = select (nfds, &read_fdset, NULL, NULL, NULL);
- if (num_set_fds < 0)
+ n = 1;
+ if (m_read_file.Read(&ch, n).Success() && n == 1)
{
- const int select_errno = errno;
-
- if (select_errno != EINTR)
+ if (m_write_file.Write(&ch, n).Fail() || n != 1)
SetIsDone(true);
}
- else if (num_set_fds > 0)
+ else
+ SetIsDone(true);
+ }
+ if (FD_ISSET (pipe_read_fd, &read_fdset))
+ {
+ size_t bytes_read;
+ // Consume the interrupt byte
+ Error error = m_pipe.Read(&ch, 1, bytes_read);
+ if (error.Success())
{
- char ch = 0;
- size_t n;
- if (FD_ISSET (read_fd, &read_fdset))
+ switch (ch)
{
- n = 1;
- if (m_read_file.Read(&ch, n).Success() && n == 1)
- {
- if (m_write_file.Write(&ch, n).Fail() || n != 1)
- SetIsDone(true);
- }
- else
+ case 'q':
SetIsDone(true);
- }
- if (FD_ISSET (pipe_read_fd, &read_fdset))
- {
- size_t bytes_read;
- // Consume the interrupt byte
- Error error = m_pipe.Read(&ch, 1, bytes_read);
- if (error.Success())
- {
- switch (ch)
- {
- case 'q':
- SetIsDone(true);
- break;
- case 'i':
- if (StateIsRunningState(m_process->GetState()))
- m_process->Halt();
- break;
- }
- }
+ break;
+ case 'i':
+ if (StateIsRunningState(m_process->GetState()))
+ m_process->Halt();
+ break;
}
}
}
-#endif
- terminal_state.Restore();
-
}
- else
- SetIsDone(true);
}
- else
- SetIsDone(true);
- }
-
- // Hide any characters that have been displayed so far so async
- // output can be displayed. Refresh() will be called after the
- // output has been displayed.
- virtual void
- Hide ()
- {
-
- }
- // Called when the async output has been received in order to update
- // the input reader (refresh the prompt and redisplay any current
- // line(s) that are being edited
- virtual void
- Refresh ()
- {
-
+#endif
+ terminal_state.Restore();
}
- virtual void
- Cancel ()
+ void
+ Cancel () override
{
char ch = 'q'; // Send 'q' for quit
size_t bytes_written = 0;
m_pipe.Write(&ch, 1, bytes_written);
}
- virtual bool
- Interrupt ()
+ bool
+ Interrupt () override
{
// 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
@@ -5111,8 +5239,8 @@ public:
return false;
}
- virtual void
- GotEOF()
+ void
+ GotEOF() override
{
}
@@ -5161,6 +5289,10 @@ Process::PushProcessIOHandler ()
IOHandlerSP io_handler_sp (m_process_input_reader);
if (io_handler_sp)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::%s pushing IO handler", __FUNCTION__);
+
io_handler_sp->SetIsDone(false);
m_target.GetDebugger().PushIOHandler (io_handler_sp);
return true;
@@ -6252,6 +6384,15 @@ Process::ClearPreResumeActions ()
m_pre_resume_actions.clear();
}
+ProcessRunLock &
+Process::GetRunLock()
+{
+ if (m_private_state_thread.EqualsThread(Host::GetCurrentThread()))
+ return m_private_run_lock;
+ else
+ return m_public_run_lock;
+}
+
void
Process::Flush ()
{
@@ -6351,13 +6492,29 @@ Process::ModulesDidLoad (ModuleList &module_list)
runtime->ModulesDidLoad(module_list);
}
+ // Let any language runtimes we have already created know
+ // about the modules that loaded.
+
+ // Iterate over a copy of this language runtime list in case
+ // the language runtime ModulesDidLoad somehow causes the language
+ // riuntime to be unloaded.
+ LanguageRuntimeCollection language_runtimes(m_language_runtimes);
+ for (const auto &pair: language_runtimes)
+ {
+ // We must check language_runtime_sp to make sure it is not
+ // NULL as we might cache the fact that we didn't have a
+ // language runtime for a language.
+ LanguageRuntimeSP language_runtime_sp = pair.second;
+ if (language_runtime_sp)
+ language_runtime_sp->ModulesDidLoad(module_list);
+ }
}
ThreadCollectionSP
Process::GetHistoryThreads(lldb::addr_t addr)
{
ThreadCollectionSP threads;
-
+
const MemoryHistorySP &memory_history = MemoryHistory::FindPlugin(shared_from_this());
if (! memory_history.get()) {
@@ -6381,3 +6538,12 @@ Process::GetInstrumentationRuntime(lldb::InstrumentationRuntimeType type)
else
return (*pos).second;
}
+
+bool
+Process::GetModuleSpec(const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec& module_spec)
+{
+ module_spec.Clear();
+ return false;
+}
diff --git a/source/Target/ProcessLaunchInfo.cpp b/source/Target/ProcessLaunchInfo.cpp
index b841b2c066a3..30c5aee63cad 100644
--- a/source/Target/ProcessLaunchInfo.cpp
+++ b/source/Target/ProcessLaunchInfo.cpp
@@ -15,6 +15,10 @@
#include "lldb/Target/FileAction.h"
#include "lldb/Target/Target.h"
+#if !defined(_WIN32)
+#include <limits.h>
+#endif
+
using namespace lldb;
using namespace lldb_private;
@@ -38,8 +42,11 @@ ProcessLaunchInfo::ProcessLaunchInfo () :
{
}
-ProcessLaunchInfo::ProcessLaunchInfo(const char *stdin_path, const char *stdout_path, const char *stderr_path,
- const char *working_directory, uint32_t launch_flags) :
+ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec,
+ const FileSpec &stdout_file_spec,
+ const FileSpec &stderr_file_spec,
+ const FileSpec &working_directory,
+ uint32_t launch_flags) :
ProcessInfo(),
m_working_dir(),
m_plugin_name(),
@@ -53,28 +60,28 @@ ProcessLaunchInfo::ProcessLaunchInfo(const char *stdin_path, const char *stdout_
m_listener_sp (),
m_hijack_listener_sp()
{
- if (stdin_path)
+ if (stdin_file_spec)
{
FileAction file_action;
const bool read = true;
const bool write = false;
- if (file_action.Open(STDIN_FILENO, stdin_path, read, write))
+ if (file_action.Open(STDIN_FILENO, stdin_file_spec, read, write))
AppendFileAction (file_action);
}
- if (stdout_path)
+ if (stdout_file_spec)
{
FileAction file_action;
const bool read = false;
const bool write = true;
- if (file_action.Open(STDOUT_FILENO, stdout_path, read, write))
+ if (file_action.Open(STDOUT_FILENO, stdout_file_spec, read, write))
AppendFileAction (file_action);
}
- if (stderr_path)
+ if (stderr_file_spec)
{
FileAction file_action;
const bool read = false;
const bool write = true;
- if (file_action.Open(STDERR_FILENO, stderr_path, read, write))
+ if (file_action.Open(STDERR_FILENO, stderr_file_spec, read, write))
AppendFileAction (file_action);
}
if (working_directory)
@@ -106,10 +113,11 @@ ProcessLaunchInfo::AppendDuplicateFileAction (int fd, int dup_fd)
}
bool
-ProcessLaunchInfo::AppendOpenFileAction (int fd, const char *path, bool read, bool write)
+ProcessLaunchInfo::AppendOpenFileAction(int fd, const FileSpec &file_spec,
+ bool read, bool write)
{
FileAction file_action;
- if (file_action.Open (fd, path, read, write))
+ if (file_action.Open(fd, file_spec, read, write))
{
AppendFileAction (file_action);
return true;
@@ -121,7 +129,7 @@ bool
ProcessLaunchInfo::AppendSuppressFileAction (int fd, bool read, bool write)
{
FileAction file_action;
- if (file_action.Open (fd, "/dev/null", read, write))
+ if (file_action.Open(fd, FileSpec{"/dev/null", false}, read, write))
{
AppendFileAction (file_action);
return true;
@@ -148,21 +156,16 @@ ProcessLaunchInfo::GetFileActionForFD(int fd) const
return NULL;
}
-const char *
-ProcessLaunchInfo::GetWorkingDirectory () const
+const FileSpec &
+ProcessLaunchInfo::GetWorkingDirectory() const
{
- if (m_working_dir.empty())
- return NULL;
- return m_working_dir.c_str();
+ return m_working_dir;
}
void
-ProcessLaunchInfo::SetWorkingDirectory (const char *working_dir)
+ProcessLaunchInfo::SetWorkingDirectory(const FileSpec &working_dir)
{
- if (working_dir && working_dir[0])
- m_working_dir.assign (working_dir);
- else
- m_working_dir.clear();
+ m_working_dir = working_dir;
}
const char *
@@ -208,14 +211,22 @@ ProcessLaunchInfo::SetLaunchInSeparateProcessGroup (bool separate)
m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
else
m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup);
+}
+void
+ProcessLaunchInfo::SetShellExpandArguments (bool expand)
+{
+ if (expand)
+ m_flags.Set(lldb::eLaunchFlagShellExpandArguments);
+ else
+ m_flags.Clear(lldb::eLaunchFlagShellExpandArguments);
}
void
ProcessLaunchInfo::Clear ()
{
ProcessInfo::Clear();
- m_working_dir.clear();
+ m_working_dir.Clear();
m_plugin_name.clear();
m_shell.Clear();
m_flags.Clear();
@@ -288,57 +299,53 @@ ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
// (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;
+ FileSpec in_file_spec;
+ FileSpec out_file_spec;
+ FileSpec err_file_spec;
if (target)
{
// Only override with the target settings if we don't already have
// an action for in, out or error
if (GetFileActionForFD(STDIN_FILENO) == NULL)
- in_path = target->GetStandardInputPath();
+ in_file_spec = target->GetStandardInputPath();
if (GetFileActionForFD(STDOUT_FILENO) == NULL)
- out_path = target->GetStandardOutputPath();
+ out_file_spec = target->GetStandardOutputPath();
if (GetFileActionForFD(STDERR_FILENO) == NULL)
- err_path = target->GetStandardErrorPath();
+ err_file_spec = target->GetStandardErrorPath();
}
if (log)
log->Printf ("ProcessLaunchInfo::%s target stdin='%s', target stdout='%s', stderr='%s'",
__FUNCTION__,
- in_path ? in_path.GetPath().c_str () : "<null>",
- out_path ? out_path.GetPath().c_str () : "<null>",
- err_path ? err_path.GetPath().c_str () : "<null>");
+ in_file_spec ? in_file_spec.GetCString() : "<null>",
+ out_file_spec ? out_file_spec.GetCString() : "<null>",
+ err_file_spec ? err_file_spec.GetCString() : "<null>");
- char path[PATH_MAX];
- if (in_path && in_path.GetPath(path, sizeof(path)))
+ if (in_file_spec)
{
- AppendOpenFileAction(STDIN_FILENO, path, true, false);
+ AppendOpenFileAction(STDIN_FILENO, in_file_spec, true, false);
if (log)
log->Printf ("ProcessLaunchInfo::%s appended stdin open file action for %s",
- __FUNCTION__,
- in_path.GetPath().c_str ());
+ __FUNCTION__, in_file_spec.GetCString());
}
- if (out_path && out_path.GetPath(path, sizeof(path)))
+ if (out_file_spec)
{
- AppendOpenFileAction(STDOUT_FILENO, path, false, true);
+ AppendOpenFileAction(STDOUT_FILENO, out_file_spec, false, true);
if (log)
log->Printf ("ProcessLaunchInfo::%s appended stdout open file action for %s",
- __FUNCTION__,
- out_path.GetPath().c_str ());
+ __FUNCTION__, out_file_spec.GetCString());
}
- if (err_path && err_path.GetPath(path, sizeof(path)))
+ if (err_file_spec)
{
+ AppendOpenFileAction(STDERR_FILENO, err_file_spec, false, true);
if (log)
log->Printf ("ProcessLaunchInfo::%s appended stderr open file action for %s",
- __FUNCTION__,
- err_path.GetPath().c_str ());
- AppendOpenFileAction(STDERR_FILENO, path, false, true);
+ __FUNCTION__, err_file_spec.GetCString());
}
- if (default_to_use_pty && (!in_path || !out_path || !err_path))
+ if (default_to_use_pty && (!in_file_spec || !out_file_spec || !err_file_spec))
{
if (log)
log->Printf ("ProcessLaunchInfo::%s default_to_use_pty is set, and at least one stdin/stderr/stdout is unset, so generating a pty to use for it",
@@ -353,27 +360,27 @@ ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
#endif
if (m_pty->OpenFirstAvailableMaster(open_flags, NULL, 0))
{
- const char *slave_path = m_pty->GetSlaveName(NULL, 0);
+ const FileSpec slave_file_spec{m_pty->GetSlaveName(NULL, 0), false};
// Only use the slave tty if we don't have anything specified for
// input and don't have an action for stdin
- if (!in_path && GetFileActionForFD(STDIN_FILENO) == NULL)
+ if (!in_file_spec && GetFileActionForFD(STDIN_FILENO) == NULL)
{
- AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
+ AppendOpenFileAction(STDIN_FILENO, slave_file_spec, true, false);
}
// Only use the slave tty if we don't have anything specified for
// output and don't have an action for stdout
- if (!out_path && GetFileActionForFD(STDOUT_FILENO) == NULL)
+ if (!out_file_spec && GetFileActionForFD(STDOUT_FILENO) == NULL)
{
- AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
+ AppendOpenFileAction(STDOUT_FILENO, slave_file_spec, false, true);
}
// Only use the slave tty if we don't have anything specified for
// error and don't have an action for stderr
- if (!err_path && GetFileActionForFD(STDERR_FILENO) == NULL)
+ if (!err_file_spec && GetFileActionForFD(STDERR_FILENO) == NULL)
{
- AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
+ AppendOpenFileAction(STDERR_FILENO, slave_file_spec, false, true);
}
}
}
@@ -416,18 +423,18 @@ ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
// is a relative path.
const char *argv0 = argv[0];
FileSpec arg_spec(argv0, false);
- if (arg_spec.IsRelativeToCurrentWorkingDirectory())
+ if (arg_spec.IsRelative())
{
// 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();
+ FileSpec 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])
+ if (working_dir)
{
- new_path += working_dir;
+ new_path += working_dir.GetPath();
}
else
{
diff --git a/source/Target/StackFrame.cpp b/source/Target/StackFrame.cpp
index 01a8c9ab88f2..7c5b022dac7c 100644
--- a/source/Target/StackFrame.cpp
+++ b/source/Target/StackFrame.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Target/StackFrame.h"
// C Includes
@@ -920,7 +918,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
}
else
{
- child_valobj_sp = valobj_sp->GetSyntheticArrayMemberFromPointer (child_index, true);
+ child_valobj_sp = valobj_sp->GetSyntheticArrayMember (child_index, true);
if (!child_valobj_sp)
{
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
@@ -1406,13 +1404,15 @@ StackFrame::Dump (Stream *strm, bool show_frame_index, bool show_fullpaths)
const bool show_module = true;
const bool show_inline = true;
const bool show_function_arguments = true;
+ const bool show_function_name = true;
m_sc.DumpStopContext (strm,
exe_ctx.GetBestExecutionContextScope(),
GetFrameCodeAddress(),
show_fullpaths,
show_module,
show_inline,
- show_function_arguments);
+ show_function_arguments,
+ show_function_name);
}
void
diff --git a/source/Target/StackFrameList.cpp b/source/Target/StackFrameList.cpp
index 9a132618288d..05923d70ce42 100644
--- a/source/Target/StackFrameList.cpp
+++ b/source/Target/StackFrameList.cpp
@@ -343,6 +343,7 @@ StackFrameList::GetFramesUpTo(uint32_t end_idx)
m_frames.push_back (unwind_frame_sp);
}
+ assert(unwind_frame_sp);
SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext (eSymbolContextBlock | eSymbolContextFunction);
Block *unwind_block = unwind_sc.block;
if (unwind_block)
@@ -354,7 +355,21 @@ StackFrameList::GetFramesUpTo(uint32_t end_idx)
// address, else we decrement the address by one to get the correct
// location.
if (idx > 0)
- curr_frame_address.Slide(-1);
+ {
+ if (curr_frame_address.GetOffset() == 0)
+ {
+ // If curr_frame_address points to the first address in a section then after
+ // adjustment it will point to an other section. In that case resolve the
+ // address again to the correct section plus offset form.
+ TargetSP target = m_thread.CalculateTarget();
+ addr_t load_addr = curr_frame_address.GetOpcodeLoadAddress(target.get());
+ curr_frame_address.SetOpcodeLoadAddress(load_addr - 1, target.get());
+ }
+ else
+ {
+ curr_frame_address.Slide(-1);
+ }
+ }
SymbolContext next_frame_sc;
Address next_frame_address;
diff --git a/source/Target/StopInfo.cpp b/source/Target/StopInfo.cpp
index 457b94c1dc20..76e5f374f952 100644
--- a/source/Target/StopInfo.cpp
+++ b/source/Target/StopInfo.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Target/StopInfo.h"
// C Includes
@@ -24,6 +22,7 @@
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/ClangUserExpression.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
@@ -39,6 +38,7 @@ StopInfo::StopInfo (Thread &thread, uint64_t value) :
m_stop_id (thread.GetProcess()->GetStopID()),
m_resume_id (thread.GetProcess()->GetResumeID()),
m_value (value),
+ m_description (),
m_override_should_notify (eLazyBoolCalculate),
m_override_should_stop (eLazyBoolCalculate),
m_extended_info()
@@ -111,7 +111,6 @@ class StopInfoBreakpoint : public StopInfo
public:
StopInfoBreakpoint (Thread &thread, break_id_t break_id) :
StopInfo (thread, break_id),
- m_description(),
m_should_stop (false),
m_should_stop_is_valid (false),
m_should_perform_action (true),
@@ -124,7 +123,6 @@ public:
StopInfoBreakpoint (Thread &thread, break_id_t break_id, bool should_stop) :
StopInfo (thread, break_id),
- m_description(),
m_should_stop (should_stop),
m_should_stop_is_valid (true),
m_should_perform_action (true),
@@ -162,6 +160,19 @@ public:
{
}
+ virtual bool
+ IsValidForOperatingSystemThread (Thread &thread)
+ {
+ ProcessSP process_sp (thread.GetProcess());
+ if (process_sp)
+ {
+ BreakpointSiteSP bp_site_sp (process_sp->GetBreakpointSiteList().FindByID (m_value));
+ if (bp_site_sp)
+ return bp_site_sp->ValidForThisThread (&thread);
+ }
+ return false;
+ }
+
virtual StopReason
GetStopReason () const
{
@@ -335,6 +346,7 @@ protected:
}
BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
+ std::unordered_set<break_id_t> precondition_breakpoints;
if (bp_site_sp)
{
@@ -346,7 +358,9 @@ protected:
}
else
{
- // We go through each location, and test first its condition. If the condition says to stop,
+ // We go through each location, and test first its precondition - this overrides everything. Note,
+ // we only do this once per breakpoint - not once per location...
+ // Then check the condition. If the condition says to stop,
// then we run the callback for that location. If that callback says to stop as well, then
// we set m_should_stop to true; we are going to stop.
// But we still want to give all the breakpoints whose conditions say we are going to stop a
@@ -442,7 +456,19 @@ protected:
}
continue;
}
- // First run the condition for the breakpoint. If that says we should stop, then we'll run
+
+ // First run the precondition, but since the precondition is per breakpoint, only run it once
+ // per breakpoint.
+ std::pair<std::unordered_set<break_id_t>::iterator, bool> result
+ = precondition_breakpoints.insert(bp_loc_sp->GetBreakpoint().GetID());
+ if (!result.second)
+ continue;
+
+ bool precondition_result = bp_loc_sp->GetBreakpoint().EvaluatePrecondition(context);
+ if (!precondition_result)
+ continue;
+
+ // Next 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)
@@ -539,7 +565,6 @@ protected:
}
private:
- std::string m_description;
bool m_should_stop;
bool m_should_stop_is_valid;
bool m_should_perform_action; // Since we are trying to preserve the "state" of the system even if we run functions
@@ -592,7 +617,6 @@ public:
StopInfoWatchpoint (Thread &thread, break_id_t watch_id) :
StopInfo(thread, watch_id),
- m_description(),
m_should_stop(false),
m_should_stop_is_valid(false)
{
@@ -831,7 +855,6 @@ protected:
}
private:
- std::string m_description;
bool m_should_stop;
bool m_should_stop_is_valid;
};
@@ -846,9 +869,10 @@ class StopInfoUnixSignal : public StopInfo
{
public:
- StopInfoUnixSignal (Thread &thread, int signo) :
+ StopInfoUnixSignal (Thread &thread, int signo, const char *description) :
StopInfo (thread, signo)
{
+ SetDescription (description);
}
virtual ~StopInfoUnixSignal ()
@@ -1136,9 +1160,9 @@ StopInfo::CreateStopReasonWithWatchpointID (Thread &thread, break_id_t watch_id)
}
StopInfoSP
-StopInfo::CreateStopReasonWithSignal (Thread &thread, int signo)
+StopInfo::CreateStopReasonWithSignal (Thread &thread, int signo, const char *description)
{
- return StopInfoSP (new StopInfoUnixSignal (thread, signo));
+ return StopInfoSP (new StopInfoUnixSignal (thread, signo, description));
}
StopInfoSP
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp
index e9393d1be0b4..6ba09f4ee948 100644
--- a/source/Target/Target.cpp
+++ b/source/Target/Target.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Target/Target.h"
// C Includes
@@ -34,7 +32,9 @@
#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Expression/ClangModulesDeclVendor.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -42,8 +42,10 @@
#include "lldb/Interpreter/OptionGroupWatchpoint.h"
#include "lldb/Interpreter/OptionValues.h"
#include "lldb/Interpreter/Property.h"
-#include "lldb/lldb-private-log.h"
+#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StackFrame.h"
@@ -83,7 +85,7 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::Plat
m_scratch_ast_context_ap (),
m_scratch_ast_source_ap (),
m_ast_importer_ap (),
- m_persistent_variables (),
+ m_persistent_variables (new ClangPersistentVariables),
m_source_manager_ap(),
m_stop_hooks (),
m_stop_hook_next_id (0),
@@ -175,6 +177,7 @@ Target::CleanupProcess ()
this->GetWatchpointList().GetListMutex(locker);
DisableAllWatchpoints(false);
ClearAllWatchpointHitCounts();
+ ClearAllWatchpointHistoricValues();
}
void
@@ -184,7 +187,7 @@ Target::DeleteCurrentProcess ()
{
m_section_load_history.Clear();
if (m_process_sp->IsAlive())
- m_process_sp->Destroy();
+ m_process_sp->Destroy(false);
m_process_sp->Finalize();
@@ -225,7 +228,7 @@ Target::Destroy()
m_last_created_watchpoint.reset();
m_search_filter_sp.reset();
m_image_search_paths.Clear(notify);
- m_persistent_variables.Clear();
+ m_persistent_variables->Clear();
m_stop_hooks.clear();
m_stop_hook_next_id = 0;
m_suppress_stop_hooks = false;
@@ -268,10 +271,13 @@ Target::CreateSourceRegexBreakpoint (const FileSpecList *containingModules,
const FileSpecList *source_file_spec_list,
RegularExpression &source_regex,
bool internal,
- bool hardware)
+ bool hardware,
+ LazyBool move_to_nearest_code)
{
SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, source_file_spec_list));
- BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex (NULL, source_regex));
+ if (move_to_nearest_code == eLazyBoolCalculate)
+ move_to_nearest_code = GetMoveToNearestCode() ? eLazyBoolYes : eLazyBoolNo;
+ BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex (NULL, source_regex, !static_cast<bool>(move_to_nearest_code)));
return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true);
}
@@ -283,7 +289,8 @@ Target::CreateBreakpoint (const FileSpecList *containingModules,
LazyBool check_inlines,
LazyBool skip_prologue,
bool internal,
- bool hardware)
+ bool hardware,
+ LazyBool move_to_nearest_code)
{
if (check_inlines == eLazyBoolCalculate)
{
@@ -320,12 +327,15 @@ Target::CreateBreakpoint (const FileSpecList *containingModules,
}
if (skip_prologue == eLazyBoolCalculate)
skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo;
+ if (move_to_nearest_code == eLazyBoolCalculate)
+ move_to_nearest_code = GetMoveToNearestCode() ? eLazyBoolYes : eLazyBoolNo;
BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine (NULL,
file,
line_no,
check_inlines,
- skip_prologue));
+ skip_prologue,
+ !static_cast<bool>(move_to_nearest_code)));
return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true);
}
@@ -518,11 +528,23 @@ Target::CreateFuncRegexBreakpoint (const FileSpecList *containingModules,
}
lldb::BreakpointSP
-Target::CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_bp, bool throw_bp, bool internal)
+Target::CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_bp, bool throw_bp, bool internal, Args *additional_args, Error *error)
{
- return LanguageRuntime::CreateExceptionBreakpoint (*this, language, catch_bp, throw_bp, internal);
+ BreakpointSP exc_bkpt_sp = LanguageRuntime::CreateExceptionBreakpoint (*this, language, catch_bp, throw_bp, internal);
+ if (exc_bkpt_sp && additional_args)
+ {
+ Breakpoint::BreakpointPreconditionSP precondition_sp = exc_bkpt_sp->GetPrecondition();
+ if (precondition_sp && additional_args)
+ {
+ if (error)
+ *error = precondition_sp->ConfigurePrecondition(*additional_args);
+ else
+ precondition_sp->ConfigurePrecondition(*additional_args);
+ }
+ }
+ return exc_bkpt_sp;
}
-
+
BreakpointSP
Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal, bool request_hardware, bool resolve_indirect_symbols)
{
@@ -907,6 +929,26 @@ Target::ClearAllWatchpointHitCounts ()
return true; // Success!
}
+// Assumption: Caller holds the list mutex lock for m_watchpoint_list.
+bool
+Target::ClearAllWatchpointHistoricValues ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("Target::%s\n", __FUNCTION__);
+
+ size_t num_watchpoints = m_watchpoint_list.GetSize();
+ for (size_t i = 0; i < num_watchpoints; ++i)
+ {
+ WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i);
+ if (!wp_sp)
+ return false;
+
+ wp_sp->ResetHistoricValues();
+ }
+ return true; // Success!
+}
+
// Assumption: Caller holds the list mutex lock for m_watchpoint_list
// during these operations.
bool
@@ -1020,13 +1062,24 @@ Target::IgnoreWatchpointByID (lldb::watch_id_t watch_id, uint32_t ignore_count)
ModuleSP
Target::GetExecutableModule ()
{
- return m_images.GetModuleAtIndex(0);
+ // search for the first executable in the module list
+ for (size_t i = 0; i < m_images.GetSize(); ++i)
+ {
+ ModuleSP module_sp = m_images.GetModuleAtIndex (i);
+ lldb_private::ObjectFile * obj = module_sp->GetObjectFile();
+ if (obj == nullptr)
+ continue;
+ if (obj->GetType() == ObjectFile::Type::eTypeExecutable)
+ return module_sp;
+ }
+ // as fall back return the first module loaded
+ return m_images.GetModuleAtIndex (0);
}
Module*
Target::GetExecutableModulePointer ()
{
- return m_images.GetModulePointerAtIndex(0);
+ return GetExecutableModule().get();
}
static void
@@ -1163,6 +1216,30 @@ Target::SetArchitecture (const ArchSpec &arch_spec)
return false;
}
+bool
+Target::MergeArchitecture (const ArchSpec &arch_spec)
+{
+ if (arch_spec.IsValid())
+ {
+ if (m_arch.IsCompatibleMatch(arch_spec))
+ {
+ // The current target arch is compatible with "arch_spec", see if we
+ // can improve our current architecture using bits from "arch_spec"
+
+ // Merge bits from arch_spec into "merged_arch" and set our architecture
+ ArchSpec merged_arch (m_arch);
+ merged_arch.MergeFrom (arch_spec);
+ return SetArchitecture(merged_arch);
+ }
+ else
+ {
+ // The new architecture is different, we just need to replace it
+ return SetArchitecture(arch_spec);
+ }
+ }
+ return false;
+}
+
void
Target::WillClearList (const ModuleList& module_list)
{
@@ -1211,8 +1288,7 @@ Target::ModulesDidLoad (ModuleList &module_list)
{
m_process_sp->ModulesDidLoad (module_list);
}
- // TODO: make event data that packages up the module_list
- BroadcastEvent (eBroadcastBitModulesLoaded, NULL);
+ BroadcastEvent (eBroadcastBitModulesLoaded, new TargetEventData (this->shared_from_this(), module_list));
}
}
@@ -1232,7 +1308,7 @@ Target::SymbolsDidLoad (ModuleList &module_list)
}
m_breakpoint_list.UpdateBreakpoints (module_list, true, false);
- BroadcastEvent(eBroadcastBitSymbolsLoaded, NULL);
+ BroadcastEvent (eBroadcastBitSymbolsLoaded, new TargetEventData (this->shared_from_this(), module_list));
}
}
@@ -1243,8 +1319,7 @@ Target::ModulesDidUnload (ModuleList &module_list, bool delete_locations)
{
UnloadModuleSections (module_list);
m_breakpoint_list.UpdateBreakpoints (module_list, false, delete_locations);
- // TODO: make event data that packages up the module_list
- BroadcastEvent (eBroadcastBitModulesUnloaded, NULL);
+ BroadcastEvent (eBroadcastBitModulesUnloaded, new TargetEventData (this->shared_from_this(), module_list));
}
}
@@ -1662,9 +1737,9 @@ Target::GetSharedModule (const ModuleSpec &module_spec, Error *error_ptr)
// module in the shared module cache.
if (m_platform_sp)
{
- FileSpec platform_file_spec;
- error = m_platform_sp->GetSharedModule (module_spec,
- module_sp,
+ error = m_platform_sp->GetSharedModule (module_spec,
+ m_process_sp.get(),
+ module_sp,
&GetExecutableSearchPaths(),
&old_module_sp,
&did_create_module);
@@ -1856,6 +1931,15 @@ Target::GetDefaultDebugFileSearchPaths ()
return FileSpecList();
}
+FileSpecList
+Target::GetDefaultClangModuleSearchPaths ()
+{
+ TargetPropertiesSP properties_sp(Target::GetGlobalProperties());
+ if (properties_sp)
+ return properties_sp->GetClangModuleSearchPaths();
+ return FileSpecList();
+}
+
ArchSpec
Target::GetDefaultArchitecture ()
{
@@ -1932,7 +2016,7 @@ Target::EvaluateExpression
lldb::ClangExpressionVariableSP persistent_var_sp;
// Only check for persistent variables the expression starts with a '$'
if (expr_cstr[0] == '$')
- persistent_var_sp = m_persistent_variables.GetVariable (expr_cstr);
+ persistent_var_sp = m_persistent_variables->GetVariable (expr_cstr);
if (persistent_var_sp)
{
@@ -1956,6 +2040,12 @@ Target::EvaluateExpression
return execution_results;
}
+ClangPersistentVariables &
+Target::GetPersistentVariables()
+{
+ return *m_persistent_variables;
+}
+
lldb::addr_t
Target::GetCallableLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const
{
@@ -2292,8 +2382,8 @@ Target::Install (ProcessLaunchInfo *launch_info)
if (is_main_executable) // TODO: add setting for always installing main executable???
{
// Always install the main executable
- remote_file.GetDirectory() = platform_sp->GetWorkingDirectory();
- remote_file.GetFilename() = module_sp->GetFileSpec().GetFilename();
+ remote_file = platform_sp->GetRemoteWorkingDirectory();
+ remote_file.AppendPathComponent(module_sp->GetFileSpec().GetFilename().GetCString());
}
}
if (remote_file)
@@ -2304,6 +2394,7 @@ Target::Install (ProcessLaunchInfo *launch_info)
module_sp->SetPlatformFileSpec(remote_file);
if (is_main_executable)
{
+ platform_sp->SetFilePermissions(remote_file, 0700);
if (launch_info)
launch_info->SetExecutableFile(remote_file, false);
}
@@ -2486,10 +2577,24 @@ Target::Launch (ProcessLaunchInfo &launch_info, Stream *stream)
if (log)
log->Printf ("Target::%s asking the platform to debug the process", __FUNCTION__);
+ // Get a weak pointer to the previous process if we have one
+ ProcessWP process_wp;
+ if (m_process_sp)
+ process_wp = m_process_sp;
m_process_sp = GetPlatform()->DebugProcess (launch_info,
debugger,
this,
error);
+
+ // Cleanup the old process since someone might still have a strong
+ // reference to this process and we would like to allow it to cleanup
+ // as much as it can without the object being destroyed. We try to
+ // lock the shared pointer and if that works, then someone else still
+ // has a strong reference to the process.
+
+ ProcessSP old_process_sp(process_wp.lock());
+ if (old_process_sp)
+ old_process_sp->Finalize();
}
else
{
@@ -2521,41 +2626,46 @@ Target::Launch (ProcessLaunchInfo &launch_info, Stream *stream)
if (error.Success())
{
- if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == false)
+ if (synchronous_execution || launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == false)
{
ListenerSP hijack_listener_sp (launch_info.GetHijackListener());
+ if (!hijack_listener_sp)
+ {
+ hijack_listener_sp.reset(new Listener("lldb.Target.Launch.hijack"));
+ launch_info.SetHijackListener(hijack_listener_sp);
+ m_process_sp->HijackProcessEvents(hijack_listener_sp.get());
+ }
StateType state = m_process_sp->WaitForProcessToStop (NULL, NULL, false, hijack_listener_sp.get(), NULL);
if (state == eStateStopped)
{
- if (!synchronous_execution)
- m_process_sp->RestoreProcessEvents ();
-
- error = m_process_sp->PrivateResume();
-
- if (error.Success())
+ if (!launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))
{
- // 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(), stream);
- const bool must_be_alive = false; // eStateExited is ok, so this must be false
- if (!StateIsStoppedState(state, must_be_alive))
+ error = m_process_sp->PrivateResume();
+ if (error.Success())
{
- error.SetErrorStringWithFormat("process isn't stopped: %s", StateAsCString(state));
+ state = m_process_sp->WaitForProcessToStop (NULL, NULL, true, hijack_listener_sp.get(), stream);
+ const bool must_be_alive = false; // eStateExited is ok, so this must be false
+ if (!StateIsStoppedState(state, must_be_alive))
+ {
+ error.SetErrorStringWithFormat("process isn't stopped: %s", StateAsCString(state));
+ }
}
}
- }
- else
- {
- Error error2;
- error2.SetErrorStringWithFormat("process resume at entry point failed: %s", error.AsCString());
- error = error2;
+ else
+ {
+ m_process_sp->RestoreProcessEvents();
+ error = m_process_sp->PrivateResume();
+ }
+ if (!error.Success())
+ {
+ Error error2;
+ error2.SetErrorStringWithFormat("process resume at entry point failed: %s", error.AsCString());
+ error = error2;
+ }
}
}
else if (state == eStateExited)
@@ -2594,6 +2704,83 @@ Target::Launch (ProcessLaunchInfo &launch_info, Stream *stream)
}
return error;
}
+
+Error
+Target::Attach (ProcessAttachInfo &attach_info, Stream *stream)
+{
+ auto state = eStateInvalid;
+ auto process_sp = GetProcessSP ();
+ if (process_sp)
+ {
+ state = process_sp->GetState ();
+ if (process_sp->IsAlive () && state != eStateConnected)
+ {
+ if (state == eStateAttaching)
+ return Error ("process attach is in progress");
+ return Error ("a process is already being debugged");
+ }
+ }
+
+ ListenerSP hijack_listener_sp (new Listener ("lldb.Target.Attach.attach.hijack"));
+ attach_info.SetHijackListener (hijack_listener_sp);
+
+ const ModuleSP old_exec_module_sp = GetExecutableModule ();
+
+ // If no process info was specified, then use the target executable
+ // name as the process to attach to by default
+ if (!attach_info.ProcessInfoSpecified ())
+ {
+ if (old_exec_module_sp)
+ attach_info.GetExecutableFile ().GetFilename () = old_exec_module_sp->GetPlatformFileSpec ().GetFilename ();
+
+ if (!attach_info.ProcessInfoSpecified ())
+ {
+ return Error ("no process specified, create a target with a file, or specify the --pid or --name");
+ }
+ }
+
+ const auto platform_sp = GetDebugger ().GetPlatformList ().GetSelectedPlatform ();
+
+ Error error;
+ if (state != eStateConnected && platform_sp != nullptr && platform_sp->CanDebugProcess ())
+ {
+ SetPlatform (platform_sp);
+ process_sp = platform_sp->Attach (attach_info, GetDebugger (), this, error);
+ }
+ else
+ {
+ if (state != eStateConnected)
+ {
+ const char *plugin_name = attach_info.GetProcessPluginName ();
+ process_sp = CreateProcess (attach_info.GetListenerForProcess (GetDebugger ()), plugin_name, nullptr);
+ if (process_sp == nullptr)
+ {
+ error.SetErrorStringWithFormat ("failed to create process using plugin %s", (plugin_name) ? plugin_name : "null");
+ return error;
+ }
+ }
+ process_sp->HijackProcessEvents (hijack_listener_sp.get ());
+ error = process_sp->Attach (attach_info);
+ }
+
+ if (error.Success () && process_sp)
+ {
+ state = process_sp->WaitForProcessToStop (nullptr, nullptr, false, attach_info.GetHijackListener ().get (), stream);
+ process_sp->RestoreProcessEvents ();
+
+ if (state != eStateStopped)
+ {
+ const char *exit_desc = process_sp->GetExitDescription ();
+ if (exit_desc)
+ error.SetErrorStringWithFormat ("attach failed: %s", exit_desc);
+ else
+ error.SetErrorString ("attach failed: process did not stop (no such process or permission problem?)");
+ process_sp->Destroy (false);
+ }
+ }
+ return error;
+}
+
//--------------------------------------------------------------
// Target::StopHook
//--------------------------------------------------------------
@@ -2625,6 +2812,12 @@ Target::StopHook::~StopHook ()
}
void
+Target::StopHook::SetSpecifier(SymbolContextSpecifier *specifier)
+{
+ m_specifier_sp.reset(specifier);
+}
+
+void
Target::StopHook::SetThreadSpecifier (ThreadSpec *specifier)
{
m_thread_spec_ap.reset (specifier);
@@ -2744,6 +2937,7 @@ static PropertyDefinition
g_properties[] =
{
{ "default-arch" , OptionValue::eTypeArch , true , 0 , NULL, NULL, "Default architecture to choose, when there's a choice." },
+ { "move-to-nearest-code" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "Move breakpoints to nearest code." },
{ "expr-prefix" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "Path to a file containing expressions to be prepended to all expressions." },
{ "prefer-dynamic-value" , OptionValue::eTypeEnum , false, eDynamicDontRunTarget , NULL, g_dynamic_value_types, "Should printed values be shown as their dynamic value." },
{ "enable-synthetic-value" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "Should synthetic values be used by default whenever available." },
@@ -2755,6 +2949,8 @@ g_properties[] =
"Each element of the array is checked in order and the first one that results in a match wins." },
{ "exec-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , NULL, NULL, "Executable search paths to use when locating executable files whose paths don't match the local file system." },
{ "debug-file-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , NULL, NULL, "List of directories to be searched when locating debug symbol files." },
+ { "clang-module-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , NULL, NULL, "List of directories to be searched when locating modules for Clang." },
+ { "auto-import-clang-modules" , OptionValue::eTypeBoolean , false, false , NULL, NULL, "Automatically load Clang modules referred to by the program." },
{ "max-children-count" , OptionValue::eTypeSInt64 , false, 256 , NULL, NULL, "Maximum number of children to expand in any level of depth." },
{ "max-string-summary-length" , OptionValue::eTypeSInt64 , false, 1024 , NULL, NULL, "Maximum number of characters to show when using %s in summary strings." },
{ "max-memory-read-size" , OptionValue::eTypeSInt64 , false, 1024 , NULL, NULL, "Maximum number of bytes that 'memory read' will fetch before --force must be specified." },
@@ -2771,7 +2967,7 @@ g_properties[] =
{ "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, eInlineBreakpointsAlways , NULL, g_inline_breakpoint_enums, "The strategy to use when settings breakpoints by file and line. "
"Breakpoint locations can end up being inlined by the compiler, so that a compile unit 'a.c' might contain an inlined function from another source file. "
- "Usually this is limitted to breakpoint locations from inlined functions from header or other include files, or more accurately non-implementation source files. "
+ "Usually this is limited to breakpoint locations from inlined functions from header or other include files, or more accurately non-implementation source files. "
"Sometimes code might #include implementation files and cause inlined breakpoint locations in inlined implementation files. "
"Always checking for inlined breakpoint locations can be expensive (memory and time), so if you have a project with many headers "
"and find that setting breakpoints is slow, then you can change this setting to headers. "
@@ -2791,11 +2987,15 @@ g_properties[] =
"'minimal' is the fastest setting and will load section data with no symbols, but should rarely be used as stack frames in these memory regions will be inaccurate and not provide any context (fastest). " },
{ "display-expression-in-crashlogs" , OptionValue::eTypeBoolean , false, false, NULL, NULL, "Expressions that crash will show up in crash logs if the host system supports executable specific crash log strings and this setting is set to true." },
{ "trap-handler-names" , OptionValue::eTypeArray , true, OptionValue::eTypeString, NULL, NULL, "A list of trap handler function names, e.g. a common Unix user process one is _sigtramp." },
+ { "display-runtime-support-values" , OptionValue::eTypeBoolean , false, false, NULL, NULL, "If true, LLDB will show variables that are meant to support the operation of a language's runtime support." },
+ { "non-stop-mode" , OptionValue::eTypeBoolean , false, 0, NULL, NULL, "Disable lock-step debugging, instead control threads independently." },
{ NULL , OptionValue::eTypeInvalid , false, 0 , NULL, NULL, NULL }
};
+
enum
{
ePropertyDefaultArch,
+ ePropertyMoveToNearestCode,
ePropertyExprPrefix,
ePropertyPreferDynamic,
ePropertyEnableSynthetic,
@@ -2803,6 +3003,8 @@ enum
ePropertySourceMap,
ePropertyExecutableSearchPaths,
ePropertyDebugFileSearchPaths,
+ ePropertyClangModuleSearchPaths,
+ ePropertyAutoImportClangModules,
ePropertyMaxChildrenCount,
ePropertyMaxSummaryLength,
ePropertyMaxMemReadSize,
@@ -2825,7 +3027,9 @@ enum
ePropertyLoadScriptFromSymbolFile,
ePropertyMemoryModuleLoadLevel,
ePropertyDisplayExpressionsInCrashlogs,
- ePropertyTrapHandlerNames
+ ePropertyTrapHandlerNames,
+ ePropertyDisplayRuntimeSupportValues,
+ ePropertyNonStopModeEnabled
};
@@ -2939,11 +3143,34 @@ protected:
// TargetProperties
//----------------------------------------------------------------------
TargetProperties::TargetProperties (Target *target) :
- Properties ()
+ Properties (),
+ m_launch_info ()
{
if (target)
{
m_collection_sp.reset (new TargetOptionValueProperties(target, Target::GetGlobalProperties()));
+
+ // Set callbacks to update launch_info whenever "settins set" updated any of these properties
+ m_collection_sp->SetValueChangedCallback(ePropertyArg0, TargetProperties::Arg0ValueChangedCallback, this);
+ m_collection_sp->SetValueChangedCallback(ePropertyRunArgs, TargetProperties::RunArgsValueChangedCallback, this);
+ m_collection_sp->SetValueChangedCallback(ePropertyEnvVars, TargetProperties::EnvVarsValueChangedCallback, this);
+ m_collection_sp->SetValueChangedCallback(ePropertyInputPath, TargetProperties::InputPathValueChangedCallback, this);
+ m_collection_sp->SetValueChangedCallback(ePropertyOutputPath, TargetProperties::OutputPathValueChangedCallback, this);
+ m_collection_sp->SetValueChangedCallback(ePropertyErrorPath, TargetProperties::ErrorPathValueChangedCallback, this);
+ m_collection_sp->SetValueChangedCallback(ePropertyDetachOnError, TargetProperties::DetachOnErrorValueChangedCallback, this);
+ m_collection_sp->SetValueChangedCallback(ePropertyDisableASLR, TargetProperties::DisableASLRValueChangedCallback, this);
+ m_collection_sp->SetValueChangedCallback(ePropertyDisableSTDIO, TargetProperties::DisableSTDIOValueChangedCallback, this);
+
+ // Update m_launch_info once it was created
+ Arg0ValueChangedCallback(this, NULL);
+ RunArgsValueChangedCallback(this, NULL);
+ //EnvVarsValueChangedCallback(this, NULL); // FIXME: cause segfault in Target::GetPlatform()
+ InputPathValueChangedCallback(this, NULL);
+ OutputPathValueChangedCallback(this, NULL);
+ ErrorPathValueChangedCallback(this, NULL);
+ DetachOnErrorValueChangedCallback(this, NULL);
+ DisableASLRValueChangedCallback(this, NULL);
+ DisableSTDIOValueChangedCallback(this, NULL);
}
else
{
@@ -2954,6 +3181,7 @@ TargetProperties::TargetProperties (Target *target) :
true,
Process::GetGlobalProperties()->GetValueProperties());
}
+
}
TargetProperties::~TargetProperties ()
@@ -2976,6 +3204,13 @@ TargetProperties::SetDefaultArchitecture (const ArchSpec& arch)
return value->SetCurrentValue(arch, true);
}
+bool
+TargetProperties::GetMoveToNearestCode() const
+{
+ const uint32_t idx = ePropertyMoveToNearestCode;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
lldb::DynamicValueType
TargetProperties::GetPreferDynamicValue() const
{
@@ -2984,6 +3219,14 @@ TargetProperties::GetPreferDynamicValue() const
}
bool
+TargetProperties::SetPreferDynamicValue (lldb::DynamicValueType d)
+{
+ const uint32_t idx = ePropertyPreferDynamic;
+ return m_collection_sp->SetPropertyAtIndexAsEnumeration(NULL, idx, d);
+}
+
+
+bool
TargetProperties::GetDisableASLR () const
{
const uint32_t idx = ePropertyDisableASLR;
@@ -3055,6 +3298,7 @@ TargetProperties::SetArg0 (const char *arg)
{
const uint32_t idx = ePropertyArg0;
m_collection_sp->SetPropertyAtIndexAsString (NULL, idx, arg);
+ m_launch_info.SetArg0(arg);
}
bool
@@ -3069,6 +3313,7 @@ TargetProperties::SetRunArguments (const Args &args)
{
const uint32_t idx = ePropertyRunArgs;
m_collection_sp->SetPropertyAtIndexFromArgs (NULL, idx, args);
+ m_launch_info.GetArguments() = args;
}
size_t
@@ -3078,6 +3323,14 @@ TargetProperties::GetEnvironmentAsArgs (Args &env) const
return m_collection_sp->GetPropertyAtIndexAsArgs (NULL, idx, env);
}
+void
+TargetProperties::SetEnvironmentFromArgs (const Args &env)
+{
+ const uint32_t idx = ePropertyEnvVars;
+ m_collection_sp->SetPropertyAtIndexFromArgs (NULL, idx, env);
+ m_launch_info.GetEnvironmentEntries() = env;
+}
+
bool
TargetProperties::GetSkipPrologue() const
{
@@ -3112,6 +3365,22 @@ TargetProperties::GetDebugFileSearchPaths ()
return option_value->GetCurrentValue();
}
+FileSpecList &
+TargetProperties::GetClangModuleSearchPaths ()
+{
+ const uint32_t idx = ePropertyClangModuleSearchPaths;
+ OptionValueFileSpecList *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList (NULL, false, idx);
+ assert(option_value);
+ return option_value->GetCurrentValue();
+}
+
+bool
+TargetProperties::GetEnableAutoImportClangModules() const
+{
+ const uint32_t idx = ePropertyAutoImportClangModules;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
bool
TargetProperties::GetEnableSyntheticValue () const
{
@@ -3260,49 +3529,182 @@ TargetProperties::SetUserSpecifiedTrapHandlerNames (const Args &args)
m_collection_sp->SetPropertyAtIndexFromArgs (NULL, idx, args);
}
-//----------------------------------------------------------------------
-// Target::TargetEventData
-//----------------------------------------------------------------------
-const ConstString &
-Target::TargetEventData::GetFlavorString ()
+bool
+TargetProperties::GetDisplayRuntimeSupportValues () const
{
- static ConstString g_flavor ("Target::TargetEventData");
- return g_flavor;
+ const uint32_t idx = ePropertyDisplayRuntimeSupportValues;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, false);
}
-const ConstString &
-Target::TargetEventData::GetFlavor () const
+void
+TargetProperties::SetDisplayRuntimeSupportValues (bool b)
{
- return TargetEventData::GetFlavorString ();
+ const uint32_t idx = ePropertyDisplayRuntimeSupportValues;
+ m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
}
-Target::TargetEventData::TargetEventData (const lldb::TargetSP &new_target_sp) :
- EventData(),
- m_target_sp (new_target_sp)
+bool
+TargetProperties::GetNonStopModeEnabled () const
{
+ const uint32_t idx = ePropertyNonStopModeEnabled;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, false);
}
-Target::TargetEventData::~TargetEventData()
+void
+TargetProperties::SetNonStopModeEnabled (bool b)
{
+ const uint32_t idx = ePropertyNonStopModeEnabled;
+ m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+}
+const ProcessLaunchInfo &
+TargetProperties::GetProcessLaunchInfo ()
+{
+ m_launch_info.SetArg0(GetArg0()); // FIXME: Arg0 callback doesn't work
+ return m_launch_info;
}
void
-Target::TargetEventData::Dump (Stream *s) const
+TargetProperties::SetProcessLaunchInfo(const ProcessLaunchInfo &launch_info)
{
+ m_launch_info = launch_info;
+ SetArg0(launch_info.GetArg0());
+ SetRunArguments(launch_info.GetArguments());
+ SetEnvironmentFromArgs(launch_info.GetEnvironmentEntries());
+ const FileAction *input_file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
+ if (input_file_action)
+ {
+ const char *input_path = input_file_action->GetPath();
+ if (input_path)
+ SetStandardInputPath(input_path);
+ }
+ const FileAction *output_file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
+ if (output_file_action)
+ {
+ const char *output_path = output_file_action->GetPath();
+ if (output_path)
+ SetStandardOutputPath(output_path);
+ }
+ const FileAction *error_file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
+ if (error_file_action)
+ {
+ const char *error_path = error_file_action->GetPath();
+ if (error_path)
+ SetStandardErrorPath(error_path);
+ }
+ SetDetachOnError(launch_info.GetFlags().Test(lldb::eLaunchFlagDetachOnError));
+ SetDisableASLR(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableASLR));
+ SetDisableSTDIO(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableSTDIO));
+}
+void
+TargetProperties::Arg0ValueChangedCallback(void *target_property_ptr, OptionValue *)
+{
+ TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr);
+ this_->m_launch_info.SetArg0(this_->GetArg0());
}
-const TargetSP
-Target::TargetEventData::GetTargetFromEvent (const lldb::EventSP &event_sp)
+void
+TargetProperties::RunArgsValueChangedCallback(void *target_property_ptr, OptionValue *)
{
- TargetSP target_sp;
+ TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr);
+ Args args;
+ if (this_->GetRunArguments(args))
+ this_->m_launch_info.GetArguments() = args;
+}
- const TargetEventData *data = GetEventDataFromEvent (event_sp.get());
- if (data)
- target_sp = data->m_target_sp;
+void
+TargetProperties::EnvVarsValueChangedCallback(void *target_property_ptr, OptionValue *)
+{
+ TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr);
+ Args args;
+ if (this_->GetEnvironmentAsArgs(args))
+ this_->m_launch_info.GetEnvironmentEntries() = args;
+}
- return target_sp;
+void
+TargetProperties::InputPathValueChangedCallback(void *target_property_ptr, OptionValue *)
+{
+ TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr);
+ this_->m_launch_info.AppendOpenFileAction(STDIN_FILENO, this_->GetStandardInputPath(), true, false);
+}
+
+void
+TargetProperties::OutputPathValueChangedCallback(void *target_property_ptr, OptionValue *)
+{
+ TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr);
+ this_->m_launch_info.AppendOpenFileAction(STDOUT_FILENO, this_->GetStandardOutputPath(), false, true);
+}
+
+void
+TargetProperties::ErrorPathValueChangedCallback(void *target_property_ptr, OptionValue *)
+{
+ TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr);
+ this_->m_launch_info.AppendOpenFileAction(STDERR_FILENO, this_->GetStandardErrorPath(), false, true);
+}
+
+void
+TargetProperties::DetachOnErrorValueChangedCallback(void *target_property_ptr, OptionValue *)
+{
+ TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr);
+ if (this_->GetDetachOnError())
+ this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDetachOnError);
+ else
+ this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDetachOnError);
+}
+
+void
+TargetProperties::DisableASLRValueChangedCallback(void *target_property_ptr, OptionValue *)
+{
+ TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr);
+ if (this_->GetDisableASLR())
+ this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDisableASLR);
+ else
+ this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDisableASLR);
+}
+
+void
+TargetProperties::DisableSTDIOValueChangedCallback(void *target_property_ptr, OptionValue *)
+{
+ TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr);
+ if (this_->GetDisableSTDIO())
+ this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDisableSTDIO);
+ else
+ this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDisableSTDIO);
+}
+
+//----------------------------------------------------------------------
+// Target::TargetEventData
+//----------------------------------------------------------------------
+
+Target::TargetEventData::TargetEventData (const lldb::TargetSP &target_sp) :
+ EventData (),
+ m_target_sp (target_sp),
+ m_module_list ()
+{
+}
+
+Target::TargetEventData::TargetEventData (const lldb::TargetSP &target_sp, const ModuleList &module_list) :
+ EventData (),
+ m_target_sp (target_sp),
+ m_module_list (module_list)
+{
+}
+
+Target::TargetEventData::~TargetEventData()
+{
+}
+
+const ConstString &
+Target::TargetEventData::GetFlavorString ()
+{
+ static ConstString g_flavor ("Target::TargetEventData");
+ return g_flavor;
+}
+
+void
+Target::TargetEventData::Dump (Stream *s) const
+{
}
const Target::TargetEventData *
@@ -3317,3 +3719,22 @@ Target::TargetEventData::GetEventDataFromEvent (const Event *event_ptr)
return NULL;
}
+TargetSP
+Target::TargetEventData::GetTargetFromEvent (const Event *event_ptr)
+{
+ TargetSP target_sp;
+ const TargetEventData *event_data = GetEventDataFromEvent (event_ptr);
+ if (event_data)
+ target_sp = event_data->m_target_sp;
+ return target_sp;
+}
+
+ModuleList
+Target::TargetEventData::GetModuleListFromEvent (const Event *event_ptr)
+{
+ ModuleList module_list;
+ const TargetEventData *event_data = GetEventDataFromEvent (event_ptr);
+ if (event_data)
+ module_list = event_data->m_module_list;
+ return module_list;
+}
diff --git a/source/Target/TargetList.cpp b/source/Target/TargetList.cpp
index bbed0fb0bc12..552e951496f2 100644
--- a/source/Target/TargetList.cpp
+++ b/source/Target/TargetList.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
// C++ Includes
// Other libraries and framework includes
@@ -293,32 +291,27 @@ TargetList::CreateTargetInternal (Debugger &debugger,
}
}
- if (!platform_sp)
+ // If we have a valid architecture, make sure the current platform is
+ // compatible with that architecture
+ if (!prefer_platform_arch && arch.IsValid())
{
- // 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 (!prefer_platform_arch && arch.IsValid())
+ if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
{
- if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
- {
- platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
- if (platform_sp)
- debugger.GetPlatformList().SetSelectedPlatform(platform_sp);
- }
+ platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
+ if (!is_dummy_target && platform_sp)
+ debugger.GetPlatformList().SetSelectedPlatform(platform_sp);
}
- else if (platform_arch.IsValid())
+ }
+ 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))
{
- // 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);
- if (platform_sp)
- debugger.GetPlatformList().SetSelectedPlatform(platform_sp);
- }
+ platform_sp = Platform::GetPlatformForArchitecture(platform_arch, &fixed_platform_arch);
+ if (!is_dummy_target && platform_sp)
+ debugger.GetPlatformList().SetSelectedPlatform(platform_sp);
}
}
@@ -419,7 +412,7 @@ TargetList::CreateTargetInternal (Debugger &debugger,
if (file.GetFileType() == FileSpec::eFileTypeDirectory)
user_exe_path_is_bundle = true;
- if (file.IsRelativeToCurrentWorkingDirectory() && user_exe_path)
+ if (file.IsRelative() && user_exe_path)
{
// Ignore paths that start with "./" and "../"
if (!((user_exe_path[0] == '.' && user_exe_path[1] == '/') ||
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
index 6fd5cdf0d15c..29ba86a7e84d 100644
--- a/source/Target/Thread.cpp
+++ b/source/Target/Thread.cpp
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
-#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
@@ -20,7 +17,10 @@
#include "lldb/Core/RegularExpression.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/OptionValueFileSpecList.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/Property.h"
#include "lldb/Symbol/Function.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
@@ -655,11 +655,6 @@ Thread::SetupForResume ()
// telling the current plan it will resume, since we might change what the current
// plan is.
-// StopReason stop_reason = lldb::eStopReasonInvalid;
-// StopInfoSP stop_info_sp = GetStopInfo();
-// if (stop_info_sp.get())
-// stop_reason = stop_info_sp->GetStopReason();
-// if (stop_reason == lldb::eStopReasonBreakpoint)
lldb::RegisterContextSP reg_ctx_sp (GetRegisterContext());
if (reg_ctx_sp)
{
@@ -725,7 +720,7 @@ Thread::ShouldResume (StateType resume_state)
// the target, 'cause that slows down single stepping. So assume that if we got to the point where
// we're about to resume, and we haven't yet had to fetch the stop reason, then it doesn't need to know
// about the fact that we are resuming...
- const uint32_t process_stop_id = GetProcess()->GetStopID();
+ const uint32_t process_stop_id = GetProcess()->GetStopID();
if (m_stop_info_stop_id == process_stop_id &&
(m_stop_info_sp && m_stop_info_sp->IsValid()))
{
@@ -1211,7 +1206,7 @@ Thread::GetReturnValueObject ()
ValueObjectSP return_valobj_sp;
return_valobj_sp = m_completed_plan_stack[i]->GetReturnValueObject();
if (return_valobj_sp)
- return return_valobj_sp;
+ return return_valobj_sp;
}
}
return ValueObjectSP();
@@ -1227,7 +1222,7 @@ Thread::GetExpressionVariable ()
ClangExpressionVariableSP expression_variable_sp;
expression_variable_sp = m_completed_plan_stack[i]->GetExpressionVariable();
if (expression_variable_sp)
- return expression_variable_sp;
+ return expression_variable_sp;
}
}
return ClangExpressionVariableSP();
@@ -2207,8 +2202,7 @@ Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_j
strm.Printf("\n");
StructuredData::ObjectSP thread_info = GetExtendedInfo();
- StructuredData::ObjectSP stop_info = m_stop_info_sp->GetExtendedInfo();
-
+
if (print_json_thread || print_json_stopinfo)
{
if (thread_info && print_json_thread)
@@ -2216,13 +2210,17 @@ Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_j
thread_info->Dump (strm);
strm.Printf("\n");
}
-
- if (stop_info && print_json_stopinfo)
+
+ if (print_json_stopinfo && m_stop_info_sp)
{
- stop_info->Dump (strm);
- strm.Printf("\n");
+ StructuredData::ObjectSP stop_info = m_stop_info_sp->GetExtendedInfo();
+ if (stop_info)
+ {
+ stop_info->Dump (strm);
+ strm.Printf("\n");
+ }
}
-
+
return true;
}
@@ -2315,7 +2313,10 @@ Thread::GetUnwinder ()
case llvm::Triple::arm:
case llvm::Triple::aarch64:
case llvm::Triple::thumb:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::hexagon:
diff --git a/source/Target/ThreadList.cpp b/source/Target/ThreadList.cpp
index db4407b4b579..d581a7c96060 100644
--- a/source/Target/ThreadList.cpp
+++ b/source/Target/ThreadList.cpp
@@ -17,6 +17,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/ConvertEnum.h"
using namespace lldb;
using namespace lldb_private;
@@ -246,8 +247,8 @@ ThreadList::ShouldStop (Event *event_ptr)
// 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
- // then should stop. This is not a big deal, since we haven't had
+ // to be created. If that happens, we will miss asking them whether
+ // they should stop. This is not a big deal since we haven't had
// a chance to hang any interesting operations on those threads yet.
collection threads_copy;
@@ -581,6 +582,7 @@ ThreadList::WillResume ()
if (thread_sp == GetSelectedThread())
{
+ // If the currently selected thread wants to run on its own, always let it.
run_only_current_thread = true;
run_me_only_list.Clear();
run_me_only_list.AddThread (thread_sp);
diff --git a/source/Target/ThreadPlan.cpp b/source/Target/ThreadPlan.cpp
index 2c9b7fce7c24..094a6bff3722 100644
--- a/source/Target/ThreadPlan.cpp
+++ b/source/Target/ThreadPlan.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Target/ThreadPlan.h"
// C Includes
@@ -22,6 +20,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConvertEnum.h"
using namespace lldb;
using namespace lldb_private;
@@ -156,6 +155,7 @@ ThreadPlan::WillResume (StateType resume_state, bool current_plan)
if (log)
{
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ assert (reg_ctx);
addr_t pc = reg_ctx->GetPC();
addr_t sp = reg_ctx->GetSP();
addr_t fp = reg_ctx->GetFP();
diff --git a/source/Target/ThreadPlanCallFunction.cpp b/source/Target/ThreadPlanCallFunction.cpp
index 5a3ebd7b1284..e742ece7ec50 100644
--- a/source/Target/ThreadPlanCallFunction.cpp
+++ b/source/Target/ThreadPlanCallFunction.cpp
@@ -14,7 +14,6 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Address.h"
@@ -22,6 +21,7 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -407,7 +407,7 @@ ThreadPlanCallFunction::DoPlanExplainsStop (Event *event_ptr)
// signal that is set not to stop. Check that here first. We just say we explain the stop
// but aren't done and everything will continue on from there.
- if (m_real_stop_info_sp->ShouldStopSynchronous(event_ptr))
+ if (m_real_stop_info_sp && m_real_stop_info_sp->ShouldStopSynchronous(event_ptr))
{
SetPlanComplete(false);
if (m_subplan_sp)
diff --git a/source/Target/ThreadPlanCallUserExpression.cpp b/source/Target/ThreadPlanCallUserExpression.cpp
index 90b8cf81171f..1773777cc4da 100644
--- a/source/Target/ThreadPlanCallUserExpression.cpp
+++ b/source/Target/ThreadPlanCallUserExpression.cpp
@@ -14,13 +14,13 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/Process.h"
@@ -41,7 +41,7 @@ ThreadPlanCallUserExpression::ThreadPlanCallUserExpression (Thread &thread,
Address &function,
llvm::ArrayRef<lldb::addr_t> args,
const EvaluateExpressionOptions &options,
- ClangUserExpression::ClangUserExpressionSP &user_expression_sp) :
+ lldb::ClangUserExpressionSP &user_expression_sp) :
ThreadPlanCallFunction (thread, function, ClangASTType(), args, options),
m_user_expression_sp (user_expression_sp)
{
diff --git a/source/Target/ThreadPlanPython.cpp b/source/Target/ThreadPlanPython.cpp
index e196d81c897a..8cb3ada428e2 100644
--- a/source/Target/ThreadPlanPython.cpp
+++ b/source/Target/ThreadPlanPython.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Target/ThreadPlan.h"
// C Includes
@@ -20,7 +18,6 @@
#include "lldb/Core/State.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
-#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
diff --git a/source/Target/ThreadPlanRunToAddress.cpp b/source/Target/ThreadPlanRunToAddress.cpp
index e2f85c0c5f5f..54ae1dc22981 100644
--- a/source/Target/ThreadPlanRunToAddress.cpp
+++ b/source/Target/ThreadPlanRunToAddress.cpp
@@ -13,7 +13,6 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Target/Target.h"
diff --git a/source/Target/ThreadPlanStepInRange.cpp b/source/Target/ThreadPlanStepInRange.cpp
index e5f057c183fb..3ee57928b1db 100644
--- a/source/Target/ThreadPlanStepInRange.cpp
+++ b/source/Target/ThreadPlanStepInRange.cpp
@@ -13,8 +13,6 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
@@ -526,6 +524,7 @@ ThreadPlanStepInRange::DoPlanExplainsStop (Event *event_ptr)
bool
ThreadPlanStepInRange::DoWillResume (lldb::StateType resume_state, bool current_plan)
{
+ m_virtual_step = false;
if (resume_state == eStateStepping && current_plan)
{
// See if we are about to step over a virtual inlined call.
diff --git a/source/Target/ThreadPlanStepInstruction.cpp b/source/Target/ThreadPlanStepInstruction.cpp
index 0f6d7b78a9ce..1ce26df78fe6 100644
--- a/source/Target/ThreadPlanStepInstruction.cpp
+++ b/source/Target/ThreadPlanStepInstruction.cpp
@@ -14,7 +14,6 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Target/Process.h"
diff --git a/source/Target/ThreadPlanStepOut.cpp b/source/Target/ThreadPlanStepOut.cpp
index 0ded99b3091d..8b702a20ccd2 100644
--- a/source/Target/ThreadPlanStepOut.cpp
+++ b/source/Target/ThreadPlanStepOut.cpp
@@ -14,13 +14,13 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/Breakpoint.h"
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Type.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
diff --git a/source/Target/ThreadPlanStepOverBreakpoint.cpp b/source/Target/ThreadPlanStepOverBreakpoint.cpp
index 6f285e25fd0b..da0326bfa914 100644
--- a/source/Target/ThreadPlanStepOverBreakpoint.cpp
+++ b/source/Target/ThreadPlanStepOverBreakpoint.cpp
@@ -13,7 +13,6 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Target/Process.h"
diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp
index a6d65e4d8116..701e93d3c4de 100644
--- a/source/Target/ThreadPlanStepOverRange.cpp
+++ b/source/Target/ThreadPlanStepOverRange.cpp
@@ -13,8 +13,6 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Symbol/Block.h"
@@ -248,7 +246,7 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
&& sc.comp_unit == m_addr_context.comp_unit
&& sc.function == m_addr_context.function)
{
- // Okay, find the next occurance of this file in the line table:
+ // Okay, find the next occurrence of this file in the line table:
LineTable *line_table = m_addr_context.comp_unit->GetLineTable();
if (line_table)
{
@@ -261,7 +259,7 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
bool step_past_remaining_inline = false;
if (entry_idx > 0)
{
- // We require the the previous line entry and the current line entry come
+ // We require the previous line entry and the current line entry come
// from the same file.
// The other requirement is that the previous line table entry be part of an
// inlined block, we don't want to step past cases where people have inlined
diff --git a/source/Target/ThreadPlanStepRange.cpp b/source/Target/ThreadPlanStepRange.cpp
index adc515cebc08..3aed85859507 100644
--- a/source/Target/ThreadPlanStepRange.cpp
+++ b/source/Target/ThreadPlanStepRange.cpp
@@ -13,8 +13,6 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-
-#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/BreakpointSite.h"
#include "lldb/Core/Disassembler.h"
@@ -245,9 +243,9 @@ ThreadPlanStepRange::InSymbol()
{
return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
}
- else if (m_addr_context.symbol)
+ else if (m_addr_context.symbol && m_addr_context.symbol->ValueIsAddress())
{
- AddressRange range(m_addr_context.symbol->GetAddress(), m_addr_context.symbol->GetByteSize());
+ AddressRange range(m_addr_context.symbol->GetAddressRef(), m_addr_context.symbol->GetByteSize());
return range.ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
}
return false;
@@ -382,8 +380,9 @@ ThreadPlanStepRange::SetNextBranchBreakpoint ()
return false;
else
{
+ Target &target = GetThread().GetProcess()->GetTarget();
uint32_t branch_index;
- branch_index = instructions->GetIndexOfNextBranchInstruction (pc_index);
+ branch_index = instructions->GetIndexOfNextBranchInstruction (pc_index, target);
Address run_to_address;
diff --git a/source/Target/ThreadPlanStepThrough.cpp b/source/Target/ThreadPlanStepThrough.cpp
index 5b50a41a6398..068d8e6584fd 100644
--- a/source/Target/ThreadPlanStepThrough.cpp
+++ b/source/Target/ThreadPlanStepThrough.cpp
@@ -13,7 +13,6 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Target/DynamicLoader.h"
diff --git a/source/Target/ThreadPlanStepUntil.cpp b/source/Target/ThreadPlanStepUntil.cpp
index fa5ab8c5d491..4c3d4a6a049e 100644
--- a/source/Target/ThreadPlanStepUntil.cpp
+++ b/source/Target/ThreadPlanStepUntil.cpp
@@ -18,7 +18,6 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/Breakpoint.h"
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
diff --git a/source/Target/ThreadPlanTracer.cpp b/source/Target/ThreadPlanTracer.cpp
index 0629eb9981ef..406708f8c396 100644
--- a/source/Target/ThreadPlanTracer.cpp
+++ b/source/Target/ThreadPlanTracer.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Target/ThreadPlan.h"
// C Includes
@@ -18,6 +16,7 @@
// Project includes
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Log.h"
@@ -25,7 +24,9 @@
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/Value.h"
+#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/Process.h"
@@ -220,7 +221,8 @@ ThreadPlanAssemblyTracer::Log ()
NULL,
NULL,
NULL,
- disassemble_format);
+ disassemble_format,
+ 0);
}
}
}
diff --git a/source/Utility/ConvertEnum.cpp b/source/Utility/ConvertEnum.cpp
new file mode 100644
index 000000000000..e108f5e75420
--- /dev/null
+++ b/source/Utility/ConvertEnum.cpp
@@ -0,0 +1,110 @@
+//===-- ConvertEnum.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/ConvertEnum.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+lldb_private::GetVoteAsCString(Vote vote)
+{
+ switch (vote)
+ {
+ case eVoteNo:
+ return "no";
+ case eVoteNoOpinion:
+ return "no opinion";
+ case eVoteYes:
+ return "yes";
+ }
+ return "invalid";
+}
+
+const char *
+lldb_private::GetSectionTypeAsCString(lldb::SectionType sect_type)
+{
+ switch (sect_type)
+ {
+ case eSectionTypeInvalid:
+ return "invalid";
+ case eSectionTypeCode:
+ return "code";
+ case eSectionTypeContainer:
+ return "container";
+ case eSectionTypeData:
+ return "data";
+ case eSectionTypeDataCString:
+ return "data-cstr";
+ case eSectionTypeDataCStringPointers:
+ return "data-cstr-ptr";
+ case eSectionTypeDataSymbolAddress:
+ return "data-symbol-addr";
+ case eSectionTypeData4:
+ return "data-4-byte";
+ case eSectionTypeData8:
+ return "data-8-byte";
+ case eSectionTypeData16:
+ return "data-16-byte";
+ case eSectionTypeDataPointers:
+ return "data-ptrs";
+ case eSectionTypeDebug:
+ return "debug";
+ case eSectionTypeZeroFill:
+ return "zero-fill";
+ case eSectionTypeDataObjCMessageRefs:
+ return "objc-message-refs";
+ case eSectionTypeDataObjCCFStrings:
+ return "objc-cfstrings";
+ case eSectionTypeDWARFDebugAbbrev:
+ return "dwarf-abbrev";
+ case eSectionTypeDWARFDebugAranges:
+ return "dwarf-aranges";
+ case eSectionTypeDWARFDebugFrame:
+ return "dwarf-frame";
+ case eSectionTypeDWARFDebugInfo:
+ return "dwarf-info";
+ case eSectionTypeDWARFDebugLine:
+ return "dwarf-line";
+ case eSectionTypeDWARFDebugLoc:
+ return "dwarf-loc";
+ case eSectionTypeDWARFDebugMacInfo:
+ return "dwarf-macinfo";
+ case eSectionTypeDWARFDebugPubNames:
+ return "dwarf-pubnames";
+ case eSectionTypeDWARFDebugPubTypes:
+ return "dwarf-pubtypes";
+ case eSectionTypeDWARFDebugRanges:
+ return "dwarf-ranges";
+ case eSectionTypeDWARFDebugStr:
+ return "dwarf-str";
+ case eSectionTypeELFSymbolTable:
+ return "elf-symbol-table";
+ case eSectionTypeELFDynamicSymbols:
+ return "elf-dynamic-symbols";
+ case eSectionTypeELFRelocationEntries:
+ return "elf-relocation-entries";
+ case eSectionTypeELFDynamicLinkInfo:
+ return "elf-dynamic-link-info";
+ case eSectionTypeDWARFAppleNames:
+ return "apple-names";
+ case eSectionTypeDWARFAppleTypes:
+ return "apple-types";
+ case eSectionTypeDWARFAppleNamespaces:
+ return "apple-namespaces";
+ case eSectionTypeDWARFAppleObjC:
+ return "apple-objc";
+ case eSectionTypeEHFrame:
+ return "eh-frame";
+ case eSectionTypeCompactUnwind:
+ return "compact-unwind";
+ case eSectionTypeOther:
+ return "regular";
+ }
+ return "unknown";
+}
diff --git a/source/Utility/JSON.cpp b/source/Utility/JSON.cpp
new file mode 100644
index 000000000000..0ba8cf4399ce
--- /dev/null
+++ b/source/Utility/JSON.cpp
@@ -0,0 +1,217 @@
+//===--------------------- JSON.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/JSON.h"
+
+using namespace lldb_private;
+
+std::string
+JSONString::json_string_quote_metachars (const std::string &s)
+{
+ if (s.find('"') == std::string::npos)
+ return s;
+
+ std::string output;
+ const size_t s_size = s.size();
+ const char *s_chars = s.c_str();
+ for (size_t i = 0; i < s_size; i++)
+ {
+ unsigned char ch = *(s_chars + i);
+ if (ch == '"')
+ {
+ output.push_back ('\\');
+ }
+ output.push_back (ch);
+ }
+ return output;
+}
+
+JSONString::JSONString () :
+JSONValue(JSONValue::Kind::String),
+m_data()
+{
+}
+
+JSONString::JSONString (const char* s) :
+JSONValue(JSONValue::Kind::String),
+m_data(s ? s : "")
+{
+}
+
+JSONString::JSONString (const std::string& s) :
+JSONValue(JSONValue::Kind::String),
+m_data(s)
+{
+}
+
+void
+JSONString::Write (Stream& s)
+{
+ s.Printf("\"%s\"", json_string_quote_metachars(m_data).c_str());
+}
+
+JSONNumber::JSONNumber () :
+JSONValue(JSONValue::Kind::Number),
+m_data(0)
+{
+}
+
+JSONNumber::JSONNumber (int64_t i) :
+JSONValue(JSONValue::Kind::Number),
+m_data(i)
+{
+}
+
+void
+JSONNumber::Write (Stream& s)
+{
+ s.Printf("%" PRId64, m_data);
+}
+
+JSONTrue::JSONTrue () :
+JSONValue(JSONValue::Kind::True)
+{
+}
+
+void
+JSONTrue::Write(Stream& s)
+{
+ s.Printf("true");
+}
+
+JSONFalse::JSONFalse () :
+JSONValue(JSONValue::Kind::False)
+{
+}
+
+void
+JSONFalse::Write(Stream& s)
+{
+ s.Printf("false");
+}
+
+JSONNull::JSONNull () :
+JSONValue(JSONValue::Kind::Null)
+{
+}
+
+void
+JSONNull::Write(Stream& s)
+{
+ s.Printf("null");
+}
+
+JSONObject::JSONObject () :
+JSONValue(JSONValue::Kind::Object)
+{
+}
+
+void
+JSONObject::Write (Stream& s)
+{
+ bool first = true;
+ s.PutChar('{');
+ auto iter = m_elements.begin(), end = m_elements.end();
+ for (;iter != end; iter++)
+ {
+ if (first)
+ first = false;
+ else
+ s.PutChar(',');
+ JSONString key(iter->first);
+ JSONValue::SP value(iter->second);
+ key.Write(s);
+ s.PutChar(':');
+ value->Write(s);
+ }
+ s.PutChar('}');
+}
+
+bool
+JSONObject::SetObject (const std::string& key,
+ JSONValue::SP value)
+{
+ if (key.empty() || nullptr == value.get())
+ return false;
+ m_elements[key] = value;
+ return true;
+}
+
+JSONValue::SP
+JSONObject::GetObject (const std::string& key)
+{
+ auto iter = m_elements.find(key), end = m_elements.end();
+ if (iter == end)
+ return JSONValue::SP();
+ return iter->second;
+}
+
+JSONArray::JSONArray () :
+JSONValue(JSONValue::Kind::Array)
+{
+}
+
+void
+JSONArray::Write (Stream& s)
+{
+ bool first = true;
+ s.PutChar('[');
+ auto iter = m_elements.begin(), end = m_elements.end();
+ for (;iter != end; iter++)
+ {
+ if (first)
+ first = false;
+ else
+ s.PutChar(',');
+ (*iter)->Write(s);
+ }
+ s.PutChar(']');
+}
+
+bool
+JSONArray::SetObject (Index i,
+ JSONValue::SP value)
+{
+ if (value.get() == nullptr)
+ return false;
+ if (i < m_elements.size())
+ {
+ m_elements[i] = value;
+ return true;
+ }
+ if (i == m_elements.size())
+ {
+ m_elements.push_back(value);
+ return true;
+ }
+ return false;
+}
+
+bool
+JSONArray::AppendObject (JSONValue::SP value)
+{
+ if (value.get() == nullptr)
+ return false;
+ m_elements.push_back(value);
+ return true;
+}
+
+JSONValue::SP
+JSONArray::GetObject (Index i)
+{
+ if (i < m_elements.size())
+ return m_elements[i];
+ return JSONValue::SP();
+}
+
+JSONArray::Size
+JSONArray::GetNumElements ()
+{
+ return m_elements.size();
+}
diff --git a/source/Utility/LLDBAssert.cpp b/source/Utility/LLDBAssert.cpp
new file mode 100644
index 000000000000..68aa872c83cf
--- /dev/null
+++ b/source/Utility/LLDBAssert.cpp
@@ -0,0 +1,36 @@
+//===--------------------- LLDBAssert.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/LLDBAssert.h"
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
+
+using namespace llvm;
+using namespace lldb_private;
+
+void
+lldb_private::lldb_assert (bool expression,
+ const char* expr_text,
+ const char* func,
+ const char* file,
+ unsigned int line)
+{
+ if (expression)
+ ;
+ else
+ {
+ errs() << format("Assertion failed: (%s), function %s, file %s, line %u\n",
+ expr_text, func, file, line);
+ errs() << "backtrace leading to the failure:\n";
+ llvm::sys::PrintStackTrace(errs());
+ errs() << "please file a bug report against lldb reporting this failure log, and as many details as possible\n";
+ }
+}
diff --git a/source/Utility/ModuleCache.cpp b/source/Utility/ModuleCache.cpp
new file mode 100644
index 000000000000..ce0df241dc22
--- /dev/null
+++ b/source/Utility/ModuleCache.cpp
@@ -0,0 +1,186 @@
+//===--------------------- ModuleCache.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ModuleCache.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/LockFile.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
+
+#include <assert.h>
+
+#include <cstdio>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+const char* kModulesSubdir = ".cache";
+const char* kLockFileName = ".lock";
+const char* kTempFileName = ".temp";
+
+FileSpec
+JoinPath (const FileSpec &path1, const char* path2)
+{
+ FileSpec result_spec (path1);
+ result_spec.AppendPathComponent (path2);
+ return result_spec;
+}
+
+Error
+MakeDirectory (const FileSpec &dir_path)
+{
+ if (dir_path.Exists ())
+ {
+ if (!dir_path.IsDirectory ())
+ return Error ("Invalid existing path");
+
+ return Error ();
+ }
+
+ return FileSystem::MakeDirectory(dir_path, eFilePermissionsDirectoryDefault);
+}
+
+FileSpec
+GetModuleDirectory (const FileSpec &root_dir_spec, const UUID &uuid)
+{
+ const auto modules_dir_spec = JoinPath (root_dir_spec, kModulesSubdir);
+ return JoinPath (modules_dir_spec, uuid.GetAsString ().c_str ());
+}
+
+Error
+CreateHostSysRootModuleLink (const FileSpec &root_dir_spec, const char *hostname, const FileSpec &platform_module_spec, const FileSpec &local_module_spec)
+{
+ const auto sysroot_module_path_spec = JoinPath (
+ JoinPath (root_dir_spec, hostname), platform_module_spec.GetPath ().c_str ());
+ if (sysroot_module_path_spec.Exists())
+ return Error ();
+
+ const auto error = MakeDirectory (FileSpec (sysroot_module_path_spec.GetDirectory ().AsCString (), false));
+ if (error.Fail ())
+ return error;
+
+ return FileSystem::Hardlink(sysroot_module_path_spec, local_module_spec);
+}
+
+} // namespace
+
+Error
+ModuleCache::Put (const FileSpec &root_dir_spec,
+ const char *hostname,
+ const ModuleSpec &module_spec,
+ const FileSpec &tmp_file)
+{
+ const auto module_spec_dir = GetModuleDirectory (root_dir_spec, module_spec.GetUUID ());
+ const auto module_file_path = JoinPath (module_spec_dir, module_spec.GetFileSpec ().GetFilename ().AsCString ());
+
+ const auto tmp_file_path = tmp_file.GetPath ();
+ const auto err_code = llvm::sys::fs::rename (tmp_file_path.c_str (), module_file_path.GetPath ().c_str ());
+ if (err_code)
+ return Error ("Failed to rename file %s to %s: %s",
+ tmp_file_path.c_str (), module_file_path.GetPath ().c_str (), err_code.message ().c_str ());
+
+ const auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname, module_spec.GetFileSpec(), module_file_path);
+ if (error.Fail ())
+ return Error ("Failed to create link to %s: %s", module_file_path.GetPath ().c_str (), error.AsCString ());
+ return Error ();
+}
+
+Error
+ModuleCache::Get (const FileSpec &root_dir_spec,
+ const char *hostname,
+ const ModuleSpec &module_spec,
+ ModuleSP &cached_module_sp,
+ bool *did_create_ptr)
+{
+ const auto find_it = m_loaded_modules.find (module_spec.GetUUID ().GetAsString());
+ if (find_it != m_loaded_modules.end ())
+ {
+ cached_module_sp = (*find_it).second.lock ();
+ if (cached_module_sp)
+ return Error ();
+ m_loaded_modules.erase (find_it);
+ }
+
+ const auto module_spec_dir = GetModuleDirectory (root_dir_spec, module_spec.GetUUID ());
+ const auto module_file_path = JoinPath (module_spec_dir, module_spec.GetFileSpec ().GetFilename ().AsCString ());
+
+ if (!module_file_path.Exists ())
+ return Error ("Module %s not found", module_file_path.GetPath ().c_str ());
+ if (module_file_path.GetByteSize () != module_spec.GetObjectSize ())
+ return Error ("Module %s has invalid file size", module_file_path.GetPath ().c_str ());
+
+ // We may have already cached module but downloaded from an another host - in this case let's create a link to it.
+ const auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname, module_spec.GetFileSpec(), module_file_path);
+ if (error.Fail ())
+ return Error ("Failed to create link to %s: %s", module_file_path.GetPath().c_str(), error.AsCString());
+
+ auto cached_module_spec (module_spec);
+ cached_module_spec.GetUUID ().Clear (); // Clear UUID since it may contain md5 content hash instead of real UUID.
+ cached_module_spec.GetFileSpec () = module_file_path;
+ cached_module_spec.GetPlatformFileSpec () = module_spec.GetFileSpec ();
+ cached_module_sp.reset (new Module (cached_module_spec));
+ if (did_create_ptr)
+ *did_create_ptr = true;
+
+ m_loaded_modules.insert (std::make_pair (module_spec.GetUUID ().GetAsString (), cached_module_sp));
+
+ return Error ();
+}
+
+Error
+ModuleCache::GetAndPut (const FileSpec &root_dir_spec,
+ const char *hostname,
+ const ModuleSpec &module_spec,
+ const Downloader &downloader,
+ lldb::ModuleSP &cached_module_sp,
+ bool *did_create_ptr)
+{
+ const auto module_spec_dir = GetModuleDirectory (root_dir_spec, module_spec.GetUUID ());
+ auto error = MakeDirectory (module_spec_dir);
+ if (error.Fail ())
+ return error;
+
+ // Open lock file.
+ const auto lock_file_spec = JoinPath (module_spec_dir, kLockFileName);
+ File lock_file (lock_file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | File::eOpenOptionCloseOnExec);
+ if (!lock_file)
+ {
+ error.SetErrorToErrno ();
+ return Error("Failed to open lock file %s: %s", lock_file_spec.GetPath ().c_str (), error.AsCString ());
+ }
+ LockFile lock (lock_file.GetDescriptor ());
+ error = lock.WriteLock (0, 1);
+ if (error.Fail ())
+ return Error("Failed to lock file %s:%s", lock_file_spec.GetPath ().c_str (), error.AsCString ());
+
+ // Check local cache for a module.
+ error = Get (root_dir_spec, hostname, module_spec, cached_module_sp, did_create_ptr);
+ if (error.Success ())
+ return error;
+
+ const auto tmp_download_file_spec = JoinPath (module_spec_dir, kTempFileName);
+ error = downloader (module_spec, tmp_download_file_spec);
+ llvm::FileRemover tmp_file_remover (tmp_download_file_spec.GetPath ().c_str ());
+ if (error.Fail ())
+ return Error("Failed to download module: %s", error.AsCString ());
+
+ // Put downloaded file into local module cache.
+ error = Put (root_dir_spec, hostname, module_spec, tmp_download_file_spec);
+ if (error.Fail ())
+ return Error ("Failed to put module into cache: %s", error.AsCString ());
+
+ tmp_file_remover.releaseFile ();
+ return Get (root_dir_spec, hostname, module_spec, cached_module_sp, did_create_ptr);
+}
diff --git a/source/Utility/ModuleCache.h b/source/Utility/ModuleCache.h
new file mode 100644
index 000000000000..791e2b35ae3d
--- /dev/null
+++ b/source/Utility/ModuleCache.h
@@ -0,0 +1,78 @@
+//===-- ModuleCache.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_ModuleCache_h_
+#define utility_ModuleCache_h_
+
+#include "lldb/lldb-types.h"
+#include "lldb/lldb-forward.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSpec.h"
+
+#include <functional>
+#include <string>
+#include <unordered_map>
+
+namespace lldb_private {
+
+class Module;
+class UUID;
+
+//----------------------------------------------------------------------
+/// @class ModuleCache ModuleCache.h "Utility/ModuleCache.h"
+/// @brief A module cache class.
+///
+/// Caches locally modules that are downloaded from remote targets.
+/// Each cached module maintains 2 views:
+/// - UUID view: /${CACHE_ROOT}/${PLATFORM_NAME}/.cache/${UUID}/${MODULE_FILENAME}
+/// - Sysroot view: /${CACHE_ROOT}/${PLATFORM_NAME}/${HOSTNAME}/${MODULE_FULL_FILEPATH}
+///
+/// UUID views stores a real module file, whereas Sysroot view holds a symbolic
+/// link to UUID-view file.
+///
+/// Example:
+/// UUID view : /tmp/lldb/remote-linux/.cache/30C94DC6-6A1F-E951-80C3-D68D2B89E576-D5AE213C/libc.so.6
+/// Sysroot view: /tmp/lldb/remote-linux/ubuntu/lib/x86_64-linux-gnu/libc.so.6
+//----------------------------------------------------------------------
+
+class ModuleCache
+{
+public:
+ using Downloader = std::function<Error (const ModuleSpec&, const FileSpec&)>;
+
+ Error
+ GetAndPut(const FileSpec &root_dir_spec,
+ const char *hostname,
+ const ModuleSpec &module_spec,
+ const Downloader &downloader,
+ lldb::ModuleSP &cached_module_sp,
+ bool *did_create_ptr);
+
+private:
+ Error
+ Put (const FileSpec &root_dir_spec,
+ const char *hostname,
+ const ModuleSpec &module_spec,
+ const FileSpec &tmp_file);
+
+ Error
+ Get (const FileSpec &root_dir_spec,
+ const char *hostname,
+ const ModuleSpec &module_spec,
+ lldb::ModuleSP &cached_module_sp,
+ bool *did_create_ptr);
+
+ std::unordered_map<std::string, lldb::ModuleWP> m_loaded_modules;
+};
+
+} // namespace lldb_private
+
+#endif // utility_ModuleCache_h_
diff --git a/source/Utility/NameMatches.cpp b/source/Utility/NameMatches.cpp
new file mode 100644
index 000000000000..e10c47e4fd9b
--- /dev/null
+++ b/source/Utility/NameMatches.cpp
@@ -0,0 +1,50 @@
+//===-- NameMatches.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/RegularExpression.h"
+#include "lldb/Utility/NameMatches.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb_private;
+
+bool
+lldb_private::NameMatches(const char *name, NameMatchType match_type, const char *match)
+{
+ if (match_type == eNameMatchIgnore)
+ return true;
+
+ if (name == match)
+ return true;
+
+ if (name && match)
+ {
+ llvm::StringRef name_sref(name);
+ llvm::StringRef match_sref(match);
+ switch (match_type)
+ {
+ case eNameMatchIgnore: // This case cannot occur: tested before
+ return true;
+ case eNameMatchEquals:
+ return name_sref == match_sref;
+ case eNameMatchContains:
+ return name_sref.find(match_sref) != llvm::StringRef::npos;
+ case eNameMatchStartsWith:
+ return name_sref.startswith(match_sref);
+ case eNameMatchEndsWith:
+ return name_sref.endswith(match_sref);
+ case eNameMatchRegularExpression:
+ {
+ RegularExpression regex(match);
+ return regex.Execute(name);
+ }
+ break;
+ }
+ }
+ return false;
+}
diff --git a/source/Utility/PseudoTerminal.cpp b/source/Utility/PseudoTerminal.cpp
index e90955d37d4c..bc3cfee226f8 100644
--- a/source/Utility/PseudoTerminal.cpp
+++ b/source/Utility/PseudoTerminal.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "lldb/Host/Config.h"
#include "lldb/Utility/PseudoTerminal.h"
#include <errno.h>
@@ -33,6 +34,7 @@ pid_t fork(void) { return 0; }
pid_t setsid(void) { return 0; }
#elif defined(__ANDROID_NDK__)
#include "lldb/Host/android/Android.h"
+int posix_openpt(int flags);
#endif
using namespace lldb_utility;
@@ -237,9 +239,11 @@ PseudoTerminal::Fork (char *error_str, size_t error_len)
{
if (error_str)
error_str[0] = '\0';
-
pid_t pid = LLDB_INVALID_PROCESS_ID;
- if (OpenFirstAvailableMaster (O_RDWR, error_str, error_len))
+#if !defined(LLDB_DISABLE_POSIX)
+ int flags = O_RDWR;
+ flags |= O_CLOEXEC;
+ if (OpenFirstAvailableMaster (flags, error_str, error_len))
{
// Successfully opened our master pseudo terminal
@@ -258,7 +262,8 @@ PseudoTerminal::Fork (char *error_str, size_t error_len)
if (OpenSlave (O_RDWR, error_str, error_len))
{
// Successfully opened slave
- // We are done with the master in the child process so lets close it
+
+ // Master FD should have O_CLOEXEC set, but let's close it just in case...
CloseMasterFileDescriptor ();
#if defined(TIOCSCTTY)
@@ -295,6 +300,7 @@ PseudoTerminal::Fork (char *error_str, size_t error_len)
// Do nothing and let the pid get returned!
}
}
+#endif
return pid;
}
diff --git a/source/Utility/StringExtractor.cpp b/source/Utility/StringExtractor.cpp
index a2cbe6cd4869..e82c83dfd093 100644
--- a/source/Utility/StringExtractor.cpp
+++ b/source/Utility/StringExtractor.cpp
@@ -143,7 +143,7 @@ StringExtractor::GetU32 (uint32_t fail_value, int base)
char *end = nullptr;
const char *start = m_packet.c_str();
const char *cstr = start + m_index;
- uint32_t result = ::strtoul (cstr, &end, base);
+ uint32_t result = static_cast<uint32_t>(::strtoul (cstr, &end, base));
if (end && end != cstr)
{
@@ -162,7 +162,7 @@ StringExtractor::GetS32 (int32_t fail_value, int base)
char *end = nullptr;
const char *start = m_packet.c_str();
const char *cstr = start + m_index;
- int32_t result = ::strtol (cstr, &end, base);
+ int32_t result = static_cast<int32_t>(::strtol (cstr, &end, base));
if (end && end != cstr)
{
diff --git a/source/Utility/StringExtractorGDBRemote.cpp b/source/Utility/StringExtractorGDBRemote.cpp
index a137d365984f..aeceaa00fa1c 100644
--- a/source/Utility/StringExtractorGDBRemote.cpp
+++ b/source/Utility/StringExtractorGDBRemote.cpp
@@ -64,6 +64,10 @@ StringExtractorGDBRemote::GetServerPacketType () const
const char *packet_cstr = m_packet.c_str();
switch (m_packet[0])
{
+
+ case '%':
+ return eServerPacketType_notify;
+
case '\x03':
if (packet_size == 1) return eServerPacketType_interrupt;
break;
@@ -136,6 +140,14 @@ StringExtractorGDBRemote::GetServerPacketType () const
if (packet_size == 2) return eServerPacketType_qC;
break;
+ case 'E':
+ if (PACKET_STARTS_WITH ("qEcho:")) return eServerPacketType_qEcho;
+ break;
+
+ case 'F':
+ if (PACKET_STARTS_WITH ("qFileLoadAddress:")) return eServerPacketType_qFileLoadAddress;
+ break;
+
case 'G':
if (PACKET_STARTS_WITH ("qGroupName:")) return eServerPacketType_qGroupName;
if (PACKET_MATCHES ("qGetWorkingDir")) return eServerPacketType_qGetWorkingDir;
@@ -160,6 +172,7 @@ StringExtractorGDBRemote::GetServerPacketType () const
case 'M':
if (PACKET_STARTS_WITH ("qMemoryRegionInfo:")) return eServerPacketType_qMemoryRegionInfo;
if (PACKET_MATCHES ("qMemoryRegionInfo")) return eServerPacketType_qMemoryRegionInfoSupported;
+ if (PACKET_STARTS_WITH ("qModuleInfo:")) return eServerPacketType_qModuleInfo;
break;
case 'P':
diff --git a/source/Utility/StringExtractorGDBRemote.h b/source/Utility/StringExtractorGDBRemote.h
index b51be7d7c28a..beb07e5b57ea 100644
--- a/source/Utility/StringExtractorGDBRemote.h
+++ b/source/Utility/StringExtractorGDBRemote.h
@@ -50,15 +50,18 @@ public:
eServerPacketType_qfProcessInfo,
eServerPacketType_qsProcessInfo,
eServerPacketType_qC,
+ eServerPacketType_qEcho,
eServerPacketType_qGroupName,
eServerPacketType_qHostInfo,
eServerPacketType_qLaunchGDBServer,
eServerPacketType_qKillSpawnedProcess,
eServerPacketType_qLaunchSuccess,
+ eServerPacketType_qModuleInfo,
eServerPacketType_qProcessInfoPID,
eServerPacketType_qSpeedTest,
eServerPacketType_qUserName,
eServerPacketType_qGetWorkingDir,
+ eServerPacketType_qFileLoadAddress,
eServerPacketType_QEnvironment,
eServerPacketType_QLaunchArch,
eServerPacketType_QSetDisableASLR,
@@ -144,6 +147,7 @@ public:
eServerPacketType__M,
eServerPacketType__m,
+ eServerPacketType_notify, // '%' notification
};
ServerPacketType
diff --git a/source/Utility/UriParser.cpp b/source/Utility/UriParser.cpp
index 1d4402feec6e..86020d17fc3e 100644
--- a/source/Utility/UriParser.cpp
+++ b/source/Utility/UriParser.cpp
@@ -11,6 +11,7 @@
// C Includes
#include <stdlib.h>
+#include <stdio.h>
// C++ Includes
// Other libraries and framework includes
diff --git a/source/lldb.cpp b/source/lldb.cpp
index 2ac8296b4d04..89bb485a612e 100644
--- a/source/lldb.cpp
+++ b/source/lldb.cpp
@@ -7,315 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/lldb-private.h"
-#include "lldb/lldb-private-log.h"
-#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/PluginManager.h"
-#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/ABI/SysV-ppc/ABISysV_ppc.h"
-#include "Plugins/ABI/SysV-ppc64/ABISysV_ppc64.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/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/ObjectFile/PECOFF/ObjectFilePECOFF.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/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
-#if defined (__APPLE__)
-#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"
-#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
-#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h"
-#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h"
-#include "Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h"
-#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
-#include "Plugins/Process/MacOSX-Kernel/ProcessKDP.h"
-#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
-#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
-#include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h"
-#include "Plugins/Platform/MacOSX/PlatformiOSSimulator.h"
-#include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h"
-#endif
-
-#include "Plugins/Process/mach-core/ProcessMachCore.h"
-
-
-#if defined (__linux__)
-#include "Plugins/Process/Linux/ProcessLinux.h"
-#endif
-
-#if defined (_WIN32)
-#include "lldb/Host/windows/windows.h"
-#include "Plugins/Process/Windows/DynamicLoaderWindows.h"
-#include "Plugins/Process/Windows/ProcessWindows.h"
-#endif
-
-#if defined (__FreeBSD__)
-#include "Plugins/Process/POSIX/ProcessPOSIX.h"
-#include "Plugins/Process/FreeBSD/ProcessFreeBSD.h"
-#endif
-
-#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
-#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
-#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
-#include "Plugins/MemoryHistory/asan/MemoryHistoryASan.h"
-#include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h"
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 ()
-{
- // Make sure we inialize only once
- static Mutex g_inited_mutex(Mutex::eMutexTypeRecursive);
- static bool g_inited = false;
-
- Mutex::Locker locker(g_inited_mutex);
- if (!g_inited)
- {
- g_inited = true;
-
-#if defined(_MSC_VER)
- const char *disable_crash_dialog_var = getenv("LLDB_DISABLE_CRASH_DIALOG");
- if (disable_crash_dialog_var && llvm::StringRef(disable_crash_dialog_var).equals_lower("true"))
- {
- // This will prevent Windows from displaying a dialog box requiring user interaction when
- // LLDB crashes. This is mostly useful when automating LLDB, for example via the test
- // suite, so that a crash in LLDB does not prevent completion of the test suite.
- ::SetErrorMode(GetErrorMode() | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
-
- _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
- _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
- _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
- _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
- _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
- _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
- }
-#endif
-
- 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();
- ABISysV_ppc::Initialize();
- ABISysV_ppc64::Initialize();
- DisassemblerLLVMC::Initialize();
- ObjectContainerBSDArchive::Initialize();
- ObjectFileELF::Initialize();
- SymbolVendorELF::Initialize();
- SymbolFileDWARF::Initialize();
- SymbolFileSymtab::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();
- MemoryHistoryASan::Initialize();
- AddressSanitizerRuntime::Initialize();
-
-#if defined (__APPLE__)
- //----------------------------------------------------------------------
- // Apple/Darwin hosted plugins
- //----------------------------------------------------------------------
- DynamicLoaderMacOSXDYLD::Initialize();
- DynamicLoaderDarwinKernel::Initialize();
- AppleObjCRuntimeV2::Initialize();
- AppleObjCRuntimeV1::Initialize();
- ObjectContainerUniversalMachO::Initialize();
- ObjectFileMachO::Initialize();
- ProcessKDP::Initialize();
- ProcessMachCore::Initialize();
- SymbolVendorMacOSX::Initialize();
- PlatformDarwinKernel::Initialize();
- PlatformRemoteiOS::Initialize();
- PlatformMacOSX::Initialize();
- PlatformiOSSimulator::Initialize();
- SystemRuntimeMacOSX::Initialize();
-#endif
-#if defined (__linux__)
- //----------------------------------------------------------------------
- // Linux hosted plugins
- //----------------------------------------------------------------------
- ProcessLinux::Initialize();
-#endif
-#if defined(_WIN32)
- DynamicLoaderWindows::Initialize();
- ProcessWindows::Initialize();
-#endif
-#if defined (__FreeBSD__)
- ProcessFreeBSD::Initialize();
-#endif
-
- //----------------------------------------------------------------------
- // Platform agnostic plugins
- //----------------------------------------------------------------------
- PlatformRemoteGDBServer::Initialize ();
- ProcessGDBRemote::Initialize();
- DynamicLoaderStatic::Initialize();
-
- // Scan for any system or user LLDB plug-ins
- PluginManager::Initialize();
-
- // The process settings need to know about installed plug-ins, so the Settings must be initialized
- // AFTER PluginManager::Initialize is called.
-
- Debugger::SettingsInitialize();
- }
-}
-
-void
-lldb_private::WillTerminate()
-{
- Host::WillTerminate();
-}
-
-void
-lldb_private::Terminate ()
-{
- Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
-
- // Terminate and unload and loaded system or user LLDB plug-ins
- PluginManager::Terminate();
- ABIMacOSX_i386::Terminate();
- ABIMacOSX_arm::Terminate();
- ABIMacOSX_arm64::Terminate();
- ABISysV_x86_64::Terminate();
- ABISysV_ppc::Terminate();
- ABISysV_ppc64::Terminate();
- DisassemblerLLVMC::Terminate();
- ObjectContainerBSDArchive::Terminate();
- ObjectFileELF::Terminate();
- SymbolVendorELF::Terminate();
- SymbolFileDWARF::Terminate();
- SymbolFileSymtab::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();
- MemoryHistoryASan::Terminate();
- AddressSanitizerRuntime::Terminate();
-
-#if defined (__APPLE__)
- DynamicLoaderMacOSXDYLD::Terminate();
- DynamicLoaderDarwinKernel::Terminate();
- AppleObjCRuntimeV2::Terminate();
- AppleObjCRuntimeV1::Terminate();
- ObjectContainerUniversalMachO::Terminate();
- ObjectFileMachO::Terminate();
- ProcessMachCore::Terminate();
- ProcessKDP::Terminate();
- SymbolVendorMacOSX::Terminate();
- PlatformMacOSX::Terminate();
- PlatformDarwinKernel::Terminate();
- PlatformRemoteiOS::Terminate();
- PlatformiOSSimulator::Terminate();
- SystemRuntimeMacOSX::Terminate();
-#endif
-
- Debugger::SettingsTerminate ();
-
-#if defined (_WIN32)
- DynamicLoaderWindows::Terminate();
-#endif
-
-#if defined (__linux__)
- ProcessLinux::Terminate();
-#endif
-
-#if defined (__FreeBSD__)
- ProcessFreeBSD::Terminate();
-#endif
-
- ProcessGDBRemote::Terminate();
- DynamicLoaderStatic::Terminate();
-
- Log::Terminate();
-}
-
#if defined (__APPLE__)
extern "C" const unsigned char liblldb_coreVersionString[];
#else
@@ -360,13 +56,13 @@ lldb_private::GetVersion ()
const char *newline_loc = strchr(version_string, '\n');
- size_t version_len = sizeof(g_version_string);
+ size_t version_len = sizeof(g_version_string) - 1;
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);
+ ::snprintf(g_version_string, version_len + 1, "%s", version_string);
}
return g_version_string;
@@ -409,97 +105,3 @@ lldb_private::GetVersion ()
return g_version_str.c_str();
#endif
}
-
-const char *
-lldb_private::GetVoteAsCString (Vote vote)
-{
- switch (vote)
- {
- case eVoteNo: return "no";
- case eVoteNoOpinion: return "no opinion";
- case eVoteYes: return "yes";
- }
- return "invalid";
-}
-
-
-const char *
-lldb_private::GetSectionTypeAsCString (SectionType sect_type)
-{
- switch (sect_type)
- {
- case eSectionTypeInvalid: return "invalid";
- case eSectionTypeCode: return "code";
- case eSectionTypeContainer: return "container";
- case eSectionTypeData: return "data";
- case eSectionTypeDataCString: return "data-cstr";
- case eSectionTypeDataCStringPointers: return "data-cstr-ptr";
- case eSectionTypeDataSymbolAddress: return "data-symbol-addr";
- case eSectionTypeData4: return "data-4-byte";
- case eSectionTypeData8: return "data-8-byte";
- case eSectionTypeData16: return "data-16-byte";
- case eSectionTypeDataPointers: return "data-ptrs";
- case eSectionTypeDebug: return "debug";
- case eSectionTypeZeroFill: return "zero-fill";
- case eSectionTypeDataObjCMessageRefs: return "objc-message-refs";
- case eSectionTypeDataObjCCFStrings: return "objc-cfstrings";
- case eSectionTypeDWARFDebugAbbrev: return "dwarf-abbrev";
- case eSectionTypeDWARFDebugAranges: return "dwarf-aranges";
- case eSectionTypeDWARFDebugFrame: return "dwarf-frame";
- case eSectionTypeDWARFDebugInfo: return "dwarf-info";
- case eSectionTypeDWARFDebugLine: return "dwarf-line";
- case eSectionTypeDWARFDebugLoc: return "dwarf-loc";
- case eSectionTypeDWARFDebugMacInfo: return "dwarf-macinfo";
- case eSectionTypeDWARFDebugPubNames: return "dwarf-pubnames";
- case eSectionTypeDWARFDebugPubTypes: return "dwarf-pubtypes";
- case eSectionTypeDWARFDebugRanges: return "dwarf-ranges";
- case eSectionTypeDWARFDebugStr: return "dwarf-str";
- case eSectionTypeELFSymbolTable: return "elf-symbol-table";
- case eSectionTypeELFDynamicSymbols: return "elf-dynamic-symbols";
- case eSectionTypeELFRelocationEntries: return "elf-relocation-entries";
- case eSectionTypeELFDynamicLinkInfo: return "elf-dynamic-link-info";
- case eSectionTypeDWARFAppleNames: return "apple-names";
- case eSectionTypeDWARFAppleTypes: return "apple-types";
- case eSectionTypeDWARFAppleNamespaces: return "apple-namespaces";
- case eSectionTypeDWARFAppleObjC: return "apple-objc";
- case eSectionTypeEHFrame: return "eh-frame";
- case eSectionTypeCompactUnwind: return "compact-unwind";
- case eSectionTypeOther: return "regular";
- }
- return "unknown";
-
-}
-
-bool
-lldb_private::NameMatches (const char *name,
- NameMatchType match_type,
- const char *match)
-{
- if (match_type == eNameMatchIgnore)
- return true;
-
- if (name == match)
- return true;
-
- if (name && match)
- {
- llvm::StringRef name_sref(name);
- llvm::StringRef match_sref(match);
- switch (match_type)
- {
- case eNameMatchIgnore: // This case cannot occur: tested before
- return true;
- case eNameMatchEquals: return name_sref == match_sref;
- case eNameMatchContains: return name_sref.find (match_sref) != llvm::StringRef::npos;
- case eNameMatchStartsWith: return name_sref.startswith (match_sref);
- case eNameMatchEndsWith: return name_sref.endswith (match_sref);
- case eNameMatchRegularExpression:
- {
- RegularExpression regex (match);
- return regex.Execute (name);
- }
- break;
- }
- }
- return false;
-}
diff --git a/tools/argdumper/argdumper.cpp b/tools/argdumper/argdumper.cpp
new file mode 100644
index 000000000000..381a9d2f4b22
--- /dev/null
+++ b/tools/argdumper/argdumper.cpp
@@ -0,0 +1,38 @@
+//===-- argdumper.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/StreamString.h"
+#include "lldb/Utility/JSON.h"
+
+#include <iostream>
+
+using namespace lldb_private;
+
+int
+main (int argc, char *argv[])
+{
+ JSONArray::SP arguments(new JSONArray());
+ for (int i = 1;
+ i < argc;
+ i++)
+ {
+ arguments->AppendObject(JSONString::SP(new JSONString(argv[i])));
+ }
+
+ JSONObject::SP object(new JSONObject());
+ object->SetObject("arguments", arguments);
+
+ StreamString ss;
+
+ object->Write(ss);
+
+ std::cout << ss.GetData() << std::endl;
+
+ return 0;
+}
diff --git a/tools/argdumper/exports b/tools/argdumper/exports
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tools/argdumper/exports
diff --git a/tools/compact-unwind/compact-unwind-dumper.c b/tools/compact-unwind/compact-unwind-dumper.c
index 0f898dbc76b4..d6bd72d93027 100644
--- a/tools/compact-unwind/compact-unwind-dumper.c
+++ b/tools/compact-unwind/compact-unwind-dumper.c
@@ -1051,7 +1051,7 @@ print_second_level_index_regular (struct baton baton)
// UNWIND_SECOND_LEVEL_REGULAR entries have a funcOffset which includes the
// functionOffset from the containing index table already. UNWIND_SECOND_LEVEL_COMPRESSED
// entries only have the offset from the containing index table functionOffset.
- // So strip off the contianing index table functionOffset value here so they can
+ // So strip off the containing index table functionOffset value here so they can
// be treated the same at the lower layers.
print_function_encoding (baton, idx, encoding, (uint32_t) -1, func_offset - baton.first_level_index_entry.functionOffset);
diff --git a/tools/driver/Driver.cpp b/tools/driver/Driver.cpp
index f02b081b8f0f..91b92d25f434 100644
--- a/tools/driver/Driver.cpp
+++ b/tools/driver/Driver.cpp
@@ -51,7 +51,6 @@ 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 *) "";
static Driver *g_driver = NULL;
// In the Driver::MainLoop, we change the terminal settings. This function is
@@ -146,16 +145,12 @@ Driver::Driver () :
// 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;
}
@@ -872,7 +867,6 @@ PrepareCommandsForSourcing (const char *commands_data, size_t commands_size, int
{
enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
- bool success = true;
::FILE *commands_file = NULL;
fds[0] = -1;
fds[1] = -1;
@@ -887,10 +881,9 @@ PrepareCommandsForSourcing (const char *commands_data, size_t commands_size, int
ssize_t nrwr = write(fds[WRITE], commands_data, commands_size);
if (nrwr < 0)
{
- fprintf(stderr, "error: write(%i, %p, %zd) failed (errno = %i) "
+ fprintf(stderr, "error: write(%i, %p, %" PRIu64 ") failed (errno = %i) "
"when trying to open LLDB commands pipe\n",
- fds[WRITE], commands_data, commands_size, errno);
- success = false;
+ fds[WRITE], commands_data, static_cast<uint64_t>(commands_size), errno);
}
else if (static_cast<size_t>(nrwr) == commands_size)
{
@@ -916,14 +909,12 @@ PrepareCommandsForSourcing (const char *commands_data, size_t commands_size, int
"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;
}
return commands_file;
@@ -956,6 +947,18 @@ CleanupAfterCommandSourcing (int fds[2])
}
+std::string
+EscapeString (std::string arg)
+{
+ std::string::size_type pos = 0;
+ while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos)
+ {
+ arg.insert (pos, 1, '\\');
+ pos += 2;
+ }
+ return '"' + arg + '"';
+}
+
void
Driver::MainLoop ()
{
@@ -1005,13 +1008,13 @@ Driver::MainLoop ()
{
char arch_name[64];
if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name)))
- commands_stream.Printf("target create --arch=%s \"%s\"", arch_name, m_option_data.m_args[0].c_str());
+ commands_stream.Printf("target create --arch=%s %s", arch_name, EscapeString(m_option_data.m_args[0]).c_str());
else
- commands_stream.Printf("target create \"%s\"", m_option_data.m_args[0].c_str());
+ commands_stream.Printf("target create %s", EscapeString(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(" --core %s", EscapeString(m_option_data.m_core_file).c_str());
}
commands_stream.Printf("\n");
@@ -1019,23 +1022,17 @@ Driver::MainLoop ()
{
commands_stream.Printf ("settings set -- target.run-args ");
for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
- {
- 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(" %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
commands_stream.Printf("\n");
}
}
else if (!m_option_data.m_core_file.empty())
{
- commands_stream.Printf("target create --core \"%s\"\n", m_option_data.m_core_file.c_str());
+ commands_stream.Printf("target create --core %s\n", EscapeString(m_option_data.m_core_file).c_str());
}
else if (!m_option_data.m_process_name.empty())
{
- commands_stream.Printf ("process attach --name \"%s\"", m_option_data.m_process_name.c_str());
+ commands_stream.Printf ("process attach --name %s", EscapeString(m_option_data.m_process_name).c_str());
if (m_option_data.m_wait_for)
commands_stream.Printf(" --waitfor");
diff --git a/tools/driver/Platform.h b/tools/driver/Platform.h
index 8995512a0f8f..c42d7e3da9d4 100644
--- a/tools/driver/Platform.h
+++ b/tools/driver/Platform.h
@@ -10,12 +10,11 @@
#ifndef lldb_Platform_h_
#define lldb_Platform_h_
-#include "lldb/Host/HostGetOpt.h"
-
#if defined( _WIN32 )
// this will stop signal.h being included
#define _INC_SIGNAL
+ #include "lldb/Host/HostGetOpt.h"
#include <io.h>
#if defined( _MSC_VER )
#include <eh.h>
@@ -93,7 +92,7 @@
extern int tcgetattr( int fildes, struct termios *termios_p );
#else
-
+ #include "lldb/Host/HostGetOpt.h"
#include <inttypes.h>
#include <libgen.h>
@@ -103,16 +102,6 @@
#include <pthread.h>
#include <sys/time.h>
-
-#if !defined(__ANDROID_NDK__)
- #include <histedit.h>
- #if defined(__FreeBSD__) || defined(__NetBSD__)
- #include <readline/readline.h>
- #else
- #include <editline/readline.h>
- #endif
-#endif
-
#endif
#endif // lldb_Platform_h_
diff --git a/tools/lldb-mi/Driver.cpp b/tools/lldb-mi/Driver.cpp
deleted file mode 100644
index 2a907636723b..000000000000
--- a/tools/lldb-mi/Driver.cpp
+++ /dev/null
@@ -1,1276 +0,0 @@
-//===-- 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
deleted file mode 100644
index 5bc97383a0c1..000000000000
--- a/tools/lldb-mi/Driver.h
+++ /dev/null
@@ -1,144 +0,0 @@
-//===-- 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
index 217913cff175..7a1bbf77d31a 100644
--- a/tools/lldb-mi/MICmdArgContext.cpp
+++ b/tools/lldb-mi/MICmdArgContext.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -30,8 +18,6 @@
// Throws: None.
//--
CMICmdArgContext::CMICmdArgContext(void)
- : m_constCharSpace(' ')
- , m_constStrSpace(" ")
{
}
@@ -44,8 +30,6 @@ CMICmdArgContext::CMICmdArgContext(void)
//--
CMICmdArgContext::CMICmdArgContext(const CMIUtilString &vrCmdLineArgsRaw)
: m_strCmdArgsAndOptions(vrCmdLineArgsRaw)
- , m_constCharSpace(' ')
- , m_constStrSpace(" ")
{
}
@@ -101,35 +85,35 @@ CMICmdArgContext::RemoveArg(const CMIUtilString &vArg)
if (vArg.empty())
return MIstatus::success;
- const MIuint nLen = vArg.length();
- const MIuint nLenCntxt = m_strCmdArgsAndOptions.length();
+ const size_t nLen = vArg.length();
+ const size_t nLenCntxt = m_strCmdArgsAndOptions.length();
if (nLen > nLenCntxt)
return MIstatus::failure;
- MIuint nExtraSpace = 0;
- MIint nPos = m_strCmdArgsAndOptions.find(vArg);
+ size_t nExtraSpace = 0;
+ size_t nPos = m_strCmdArgsAndOptions.find(vArg);
while (1)
{
- if (nPos == (MIint)std::string::npos)
+ if (nPos == std::string::npos)
return MIstatus::success;
bool bPass1 = false;
if (nPos != 0)
{
- if (m_strCmdArgsAndOptions[nPos - 1] == m_constCharSpace)
+ if (m_strCmdArgsAndOptions[nPos - 1] == ' ')
bPass1 = true;
}
else
bPass1 = true;
- const MIuint nEnd = nPos + nLen;
+ const size_t nEnd = nPos + nLen;
if (bPass1)
{
bool bPass2 = false;
if (nEnd < nLenCntxt)
{
- if (m_strCmdArgsAndOptions[nEnd] == m_constCharSpace)
+ if (m_strCmdArgsAndOptions[nEnd] == ' ')
{
bPass2 = true;
nExtraSpace = 1;
@@ -145,7 +129,7 @@ CMICmdArgContext::RemoveArg(const CMIUtilString &vArg)
nPos = m_strCmdArgsAndOptions.find(vArg, nEnd);
}
- const MIuint nPosEnd = nLen + nExtraSpace;
+ const size_t nPosEnd = nLen + nExtraSpace;
m_strCmdArgsAndOptions = m_strCmdArgsAndOptions.replace(nPos, nPosEnd, "").c_str();
m_strCmdArgsAndOptions = m_strCmdArgsAndOptions.Trim();
@@ -182,7 +166,7 @@ CMICmdArgContext::RemoveArgAtPos(const CMIUtilString &vArg, const MIuint nArgInd
// Single words
strBuildContextUp += rWord;
if (bSpaceRequired)
- strBuildContextUp += m_constStrSpace;
+ strBuildContextUp += " ";
}
else
{
@@ -193,7 +177,7 @@ CMICmdArgContext::RemoveArgAtPos(const CMIUtilString &vArg, const MIuint nArgInd
while (vArg != words)
{
if (bSpaceRequired)
- words += m_constStrSpace;
+ words += " ";
words += *it;
if (++it == itEnd)
break;
@@ -225,7 +209,7 @@ MIuint
CMICmdArgContext::GetNumberArgsPresent(void) const
{
CMIUtilString::VecString_t vecOptions;
- return m_strCmdArgsAndOptions.SplitConsiderQuotes(m_constStrSpace, vecOptions);
+ return m_strCmdArgsAndOptions.SplitConsiderQuotes(" ", vecOptions);
}
//++ ------------------------------------------------------------------------------------
@@ -239,7 +223,7 @@ CMIUtilString::VecString_t
CMICmdArgContext::GetArgs(void) const
{
CMIUtilString::VecString_t vecOptions;
- m_strCmdArgsAndOptions.SplitConsiderQuotes(m_constStrSpace, vecOptions);
+ m_strCmdArgsAndOptions.SplitConsiderQuotes(" ", vecOptions);
return vecOptions;
}
diff --git a/tools/lldb-mi/MICmdArgContext.h b/tools/lldb-mi/MICmdArgContext.h
index 7178373ce380..baeb9232ef50 100644
--- a/tools/lldb-mi/MICmdArgContext.h
+++ b/tools/lldb-mi/MICmdArgContext.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -56,6 +44,4 @@ class CMICmdArgContext
// 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
index 290f9eef8a9d..3d63a6138f7f 100644
--- a/tools/lldb-mi/MICmdArgSet.cpp
+++ b/tools/lldb-mi/MICmdArgSet.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -181,28 +169,24 @@ CMICmdArgSet::Validate(const CMIUtilString &vStrMiCmd, CMICmdArgContext &vwCmdAr
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->GetFound())
{
if (pArg->GetIsMissingOptions())
m_setCmdArgsMissingInfo.push_back(const_cast<CMICmdArgValBase *>(pArg));
else if (!pArg->GetValid())
m_setCmdArgsThatNotValid.push_back(const_cast<CMICmdArgValBase *>(pArg));
}
+ else if (pArg->GetIsMandatory())
+ m_setCmdArgsThatAreMissing.push_back(const_cast<CMICmdArgValBase *>(pArg));
}
+
if (pArg->GetFound() && !pArg->GetIsHandledByCmd())
{
m_bIsArgsPresentButNotHandledByCmd = true;
@@ -213,14 +197,7 @@ CMICmdArgSet::Validate(const CMIUtilString &vStrMiCmd, CMICmdArgContext &vwCmdAr
++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;
- }
-
+ // report any issues with arguments/options
if (IsArgsPresentButNotHandledByCmd())
WarningArgsNotHandledbyCmdLogFile(vStrMiCmd);
diff --git a/tools/lldb-mi/MICmdArgSet.h b/tools/lldb-mi/MICmdArgSet.h
index eed667071733..00da679d7733 100644
--- a/tools/lldb-mi/MICmdArgSet.h
+++ b/tools/lldb-mi/MICmdArgSet.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmdArgValBase.cpp b/tools/lldb-mi/MICmdArgValBase.cpp
index 1419df3206c8..dfaacbc6e7b2 100644
--- a/tools/lldb-mi/MICmdArgValBase.cpp
+++ b/tools/lldb-mi/MICmdArgValBase.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdArgValBase.h b/tools/lldb-mi/MICmdArgValBase.h
index 0afe8d9bab6a..0d0eedd6e5b7 100644
--- a/tools/lldb-mi/MICmdArgValBase.h
+++ b/tools/lldb-mi/MICmdArgValBase.h
@@ -1,4 +1,4 @@
-//===-- Platform.h ----------------------------------------------*- C++ -*-===//
+//===-- CMICmdArgValBase.h --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmdArgValConsume.cpp b/tools/lldb-mi/MICmdArgValConsume.cpp
index 041005567393..c2fe9940d878 100644
--- a/tools/lldb-mi/MICmdArgValConsume.cpp
+++ b/tools/lldb-mi/MICmdArgValConsume.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -71,7 +59,7 @@ bool
CMICmdArgValConsume::Validate(CMICmdArgContext &vwArgContext)
{
if (vwArgContext.IsEmpty())
- return MIstatus::success;
+ return m_bMandatory ? MIstatus::failure : MIstatus::success;
// Consume the optional file, line, linenum arguments till the mode '--' argument
const CMIUtilString::VecString_t vecOptions(vwArgContext.GetArgs());
@@ -80,15 +68,15 @@ CMICmdArgValConsume::Validate(CMICmdArgContext &vwArgContext)
{
const CMIUtilString & rTxt( *it );
- if ( rTxt.compare( "--" ) == 0 )
+ if ( rTxt.compare( "--" ) == 0 )
{
m_bFound = true;
m_bValid = true;
- return MIstatus::success;
- }
+ return MIstatus::success;
+ }
- if ( !vwArgContext.RemoveArg( rTxt ) )
- return MIstatus::failure;
+ if ( !vwArgContext.RemoveArg( rTxt ) )
+ return MIstatus::failure;
// Next
++it;
diff --git a/tools/lldb-mi/MICmdArgValConsume.h b/tools/lldb-mi/MICmdArgValConsume.h
index 2b26e33aa8c1..1d37b79eba14 100644
--- a/tools/lldb-mi/MICmdArgValConsume.h
+++ b/tools/lldb-mi/MICmdArgValConsume.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmdArgValFile.cpp b/tools/lldb-mi/MICmdArgValFile.cpp
index cee811f24dee..400610ff6ba6 100644
--- a/tools/lldb-mi/MICmdArgValFile.cpp
+++ b/tools/lldb-mi/MICmdArgValFile.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -72,7 +60,7 @@ bool
CMICmdArgValFile::Validate(CMICmdArgContext &vwArgContext)
{
if (vwArgContext.IsEmpty())
- return MIstatus::success;
+ return m_bMandatory ? MIstatus::failure : MIstatus::success;
// The GDB/MI spec suggests there is only parameter
@@ -133,9 +121,9 @@ 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)
+ const char cSpace = ' ';
+ const size_t nPos = fileNamePath.find(cSpace);
+ if (nPos != std::string::npos)
fileNamePath = CMIUtilString::Format("\"%s\"", fileNamePath.c_str());
return fileNamePath;
@@ -158,7 +146,7 @@ CMICmdArgValFile::IsFilePath(const CMIUtilString &vrFileNamePath) const
const bool bHaveBckSlash = (vrFileNamePath.find_first_of("\\") != std::string::npos);
// Look for --someLongOption
- MIint nPos = vrFileNamePath.find_first_of("--");
+ size_t nPos = vrFileNamePath.find_first_of("--");
const bool bLong = (nPos == 0);
if (bLong)
return false;
@@ -193,13 +181,14 @@ CMICmdArgValFile::IsFilePath(const CMIUtilString &vrFileNamePath) const
bool
CMICmdArgValFile::IsValidChars(const CMIUtilString &vrText) const
{
- const MIchar *pPtr = const_cast<MIchar *>(vrText.c_str());
+ static CMIUtilString s_strSpecialCharacters(".'\"`@#$%^&*()_+-={}[]| ");
+ const char *pPtr = vrText.c_str();
for (MIuint i = 0; i < vrText.length(); i++, pPtr++)
{
- const MIchar c = *pPtr;
+ const char c = *pPtr;
if (::isalnum((int)c) == 0)
{
- if ((c != '.') && (c != '-') && (c != '_'))
+ if (s_strSpecialCharacters.find(c) == CMIUtilString::npos)
return false;
}
}
diff --git a/tools/lldb-mi/MICmdArgValFile.h b/tools/lldb-mi/MICmdArgValFile.h
index db5380885783..196f21fb3b34 100644
--- a/tools/lldb-mi/MICmdArgValFile.h
+++ b/tools/lldb-mi/MICmdArgValFile.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmdArgValListBase.cpp b/tools/lldb-mi/MICmdArgValListBase.cpp
index b992b307e346..61d72fb823c7 100644
--- a/tools/lldb-mi/MICmdArgValListBase.cpp
+++ b/tools/lldb-mi/MICmdArgValListBase.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdArgValListBase.h b/tools/lldb-mi/MICmdArgValListBase.h
index 0e56f6dac021..153af814dcfc 100644
--- a/tools/lldb-mi/MICmdArgValListBase.h
+++ b/tools/lldb-mi/MICmdArgValListBase.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmdArgValListOfN.cpp b/tools/lldb-mi/MICmdArgValListOfN.cpp
index 9a4711485f0b..8e479d52e79a 100644
--- a/tools/lldb-mi/MICmdArgValListOfN.cpp
+++ b/tools/lldb-mi/MICmdArgValListOfN.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -86,7 +74,7 @@ CMICmdArgValListOfN::Validate(CMICmdArgContext &vwArgContext)
}
if (vwArgContext.IsEmpty())
- return MIstatus::success;
+ return m_bMandatory ? MIstatus::failure : MIstatus::success;
const CMIUtilString &rArg(vwArgContext.GetArgsLeftToParse());
if (IsListOfN(rArg) && CreateList(rArg))
diff --git a/tools/lldb-mi/MICmdArgValListOfN.h b/tools/lldb-mi/MICmdArgValListOfN.h
index 48ee77f79e72..356b494c0898 100644
--- a/tools/lldb-mi/MICmdArgValListOfN.h
+++ b/tools/lldb-mi/MICmdArgValListOfN.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -56,7 +44,7 @@ class CMICmdArgValListOfN : public CMICmdArgValListBase
const ArgValType_e veType);
//
const VecArgObjPtr_t &GetExpectedOptions(void) const;
- template <class T1, typename T2> bool GetExpectedOption(T2 &vrwValue) const;
+ template <class T1, typename T2> bool GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt = 0) const;
// Overridden:
public:
@@ -76,6 +64,7 @@ class CMICmdArgValListOfN : public CMICmdArgValListBase
// parsed from the command's options string.
// Type: Template method.
// Args: vrwValue - (W) Templated type return value.
+// vnAt - (R) Value at the specific position.
// 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.
@@ -84,10 +73,13 @@ class CMICmdArgValListOfN : public CMICmdArgValListBase
//--
template <class T1, typename T2>
bool
-CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue) const
+CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt) const
{
const VecArgObjPtr_t &rVecOptions(GetExpectedOptions());
- VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin();
+ if (rVecOptions.size() <= vnAt)
+ return MIstatus::failure;
+
+ VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin() + vnAt;
if (it2 != rVecOptions.end())
{
const T1 *pOption = static_cast<T1 *>(*it2);
diff --git a/tools/lldb-mi/MICmdArgValNumber.cpp b/tools/lldb-mi/MICmdArgValNumber.cpp
index 8b1878df028b..75e9700c874d 100644
--- a/tools/lldb-mi/MICmdArgValNumber.cpp
+++ b/tools/lldb-mi/MICmdArgValNumber.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -31,21 +19,25 @@
// Throws: None.
//--
CMICmdArgValNumber::CMICmdArgValNumber(void)
- : m_nNumber(0)
+ : m_nNumberFormatMask(CMICmdArgValNumber::eArgValNumberFormat_Decimal)
+ , 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.
+// 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.
+// vnNumberFormatMask - (R) Mask of the number formats. (Dflt = CMICmdArgValNumber::eArgValNumberFormat_Decimal)
// Return: None.
// Throws: None.
//--
-CMICmdArgValNumber::CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd)
+CMICmdArgValNumber::CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd,
+ const MIuint vnNumberFormatMask /* = CMICmdArgValNumber::eArgValNumberFormat_Decimal*/)
: CMICmdArgValBaseTemplate(vrArgName, vbMandatory, vbHandleByCmd)
+ , m_nNumberFormatMask(vnNumberFormatMask)
, m_nNumber(0)
{
}
@@ -74,7 +66,7 @@ bool
CMICmdArgValNumber::Validate(CMICmdArgContext &vwArgContext)
{
if (vwArgContext.IsEmpty())
- return MIstatus::success;
+ return m_bMandatory ? MIstatus::failure : MIstatus::success;
if (vwArgContext.GetNumberArgsPresent() == 1)
{
@@ -128,11 +120,20 @@ CMICmdArgValNumber::Validate(CMICmdArgContext &vwArgContext)
bool
CMICmdArgValNumber::IsArgNumber(const CMIUtilString &vrTxt) const
{
+ const bool bFormatDecimal(m_nNumberFormatMask & CMICmdArgValNumber::eArgValNumberFormat_Decimal);
+ const bool bFormatHexadecimal(m_nNumberFormatMask & CMICmdArgValNumber::eArgValNumberFormat_Hexadecimal);
+
// Look for --someLongOption
if (std::string::npos != vrTxt.find("--"))
return false;
- return vrTxt.IsNumber();
+ if (bFormatDecimal && vrTxt.IsNumber())
+ return true;
+
+ if (bFormatHexadecimal && vrTxt.IsHexadecimalNumber())
+ return true;
+
+ return false;
}
//++ ------------------------------------------------------------------------------------
@@ -150,7 +151,7 @@ CMICmdArgValNumber::ExtractNumber(const CMIUtilString &vrTxt)
bool bOk = vrTxt.ExtractNumber(nNumber);
if (bOk)
{
- m_nNumber = static_cast<MIint>(nNumber);
+ m_nNumber = static_cast<MIint64>(nNumber);
}
return bOk;
diff --git a/tools/lldb-mi/MICmdArgValNumber.h b/tools/lldb-mi/MICmdArgValNumber.h
index 1a782e1af388..fea94b698f74 100644
--- a/tools/lldb-mi/MICmdArgValNumber.h
+++ b/tools/lldb-mi/MICmdArgValNumber.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -40,10 +28,24 @@ class CMICmdArgContext;
//--
class CMICmdArgValNumber : public CMICmdArgValBaseTemplate<MIint64>
{
+ // Enums:
+ public:
+ //++ ---------------------------------------------------------------------------------
+ // Details: CMICmdArgValNumber needs to know what format of argument to look for in
+ // the command options text.
+ //--
+ enum ArgValNumberFormat_e
+ {
+ eArgValNumberFormat_Decimal = (1u << 0),
+ eArgValNumberFormat_Hexadecimal = (1u << 1),
+ eArgValNumberFormat_Auto = ((eArgValNumberFormat_Hexadecimal << 1) - 1u) ///< Indicates to try and lookup everything up during a query.
+ };
+
// Methods:
public:
/* ctor */ CMICmdArgValNumber(void);
- /* ctor */ CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd);
+ /* ctor */ CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd,
+ const MIuint vnNumberFormatMask = eArgValNumberFormat_Decimal);
//
bool IsArgNumber(const CMIUtilString &vrTxt) const;
@@ -61,5 +63,6 @@ class CMICmdArgValNumber : public CMICmdArgValBaseTemplate<MIint64>
// Attributes:
private:
+ MIuint m_nNumberFormatMask;
MIint64 m_nNumber;
};
diff --git a/tools/lldb-mi/MICmdArgValOptionLong.cpp b/tools/lldb-mi/MICmdArgValOptionLong.cpp
index 0c29982e2634..0eaf6e0d055f 100644
--- a/tools/lldb-mi/MICmdArgValOptionLong.cpp
+++ b/tools/lldb-mi/MICmdArgValOptionLong.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -120,7 +108,7 @@ bool
CMICmdArgValOptionLong::Validate(CMICmdArgContext &vwArgContext)
{
if (vwArgContext.IsEmpty())
- return MIstatus::success;
+ return m_bMandatory ? MIstatus::failure : MIstatus::success;
if (vwArgContext.GetNumberArgsPresent() == 1)
{
@@ -266,7 +254,7 @@ CMICmdArgValOptionLong::IsArgLongOption(const CMIUtilString &vrTxt) const
if (bHavePosSlash || bHaveBckSlash)
return false;
- const MIint nPos = vrTxt.find_first_of("--");
+ const size_t nPos = vrTxt.find_first_of("--");
if (nPos != 0)
return false;
diff --git a/tools/lldb-mi/MICmdArgValOptionLong.h b/tools/lldb-mi/MICmdArgValOptionLong.h
index 8ff92bf84369..ace939b64f83 100644
--- a/tools/lldb-mi/MICmdArgValOptionLong.h
+++ b/tools/lldb-mi/MICmdArgValOptionLong.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmdArgValOptionShort.cpp b/tools/lldb-mi/MICmdArgValOptionShort.cpp
index 5a2b491d3c72..25eac676f5f9 100644
--- a/tools/lldb-mi/MICmdArgValOptionShort.cpp
+++ b/tools/lldb-mi/MICmdArgValOptionShort.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdArgValOptionShort.h b/tools/lldb-mi/MICmdArgValOptionShort.h
index 3bd38ac72d20..971a0d3a148c 100644
--- a/tools/lldb-mi/MICmdArgValOptionShort.h
+++ b/tools/lldb-mi/MICmdArgValOptionShort.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmdArgValPrintValues.cpp b/tools/lldb-mi/MICmdArgValPrintValues.cpp
new file mode 100644
index 000000000000..3030782a3a29
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValPrintValues.cpp
@@ -0,0 +1,129 @@
+//===-- MICmdArgValPrintValues.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 "MICmdArgValPrintValues.h"
+#include "MICmdArgContext.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValPrintValues constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValPrintValues::CMICmdArgValPrintValues(void)
+ : m_nPrintValues(0)
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValPrintValues 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.
+//--
+CMICmdArgValPrintValues::CMICmdArgValPrintValues(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd)
+ : CMICmdArgValBaseTemplate(vrArgName, vbMandatory, vbHandleByCmd)
+ , m_nPrintValues(0)
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValPrintValues destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValPrintValues::~CMICmdArgValPrintValues(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
+CMICmdArgValPrintValues::Validate(CMICmdArgContext &vwArgContext)
+{
+ if (vwArgContext.IsEmpty())
+ return m_bMandatory ? MIstatus::failure : MIstatus::success;
+
+ const CMIUtilString strArg(vwArgContext.GetArgs()[0]);
+ if (IsArgPrintValues(strArg) && ExtractPrintValues(strArg))
+ {
+ m_bFound = true;
+ m_bValid = true;
+ m_argValue = GetPrintValues();
+ vwArgContext.RemoveArg(strArg);
+ 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
+CMICmdArgValPrintValues::IsArgPrintValues(const CMIUtilString &vrTxt) const
+{
+ return (CMIUtilString::Compare(vrTxt, "0") || CMIUtilString::Compare(vrTxt, "--no-values") ||
+ CMIUtilString::Compare(vrTxt, "1") || CMIUtilString::Compare(vrTxt, "--all-values") ||
+ CMIUtilString::Compare(vrTxt, "2") || CMIUtilString::Compare(vrTxt, "--simple-values"));
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Extract the print-values from the print-values argument.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool
+CMICmdArgValPrintValues::ExtractPrintValues(const CMIUtilString &vrTxt)
+{
+ if (CMIUtilString::Compare(vrTxt, "0") || CMIUtilString::Compare(vrTxt, "--no-values"))
+ m_nPrintValues = 0;
+ else if (CMIUtilString::Compare(vrTxt, "1") || CMIUtilString::Compare(vrTxt, "--all-values"))
+ m_nPrintValues = 1;
+ else if (CMIUtilString::Compare(vrTxt, "2") || CMIUtilString::Compare(vrTxt, "--simple-values"))
+ m_nPrintValues = 2;
+ else
+ return MIstatus::failure;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the print-values found in the argument.
+// Type: Method.
+// Args: None.
+// Return: MIuint - The print-values.
+// Throws: None.
+//--
+MIuint
+CMICmdArgValPrintValues::GetPrintValues(void) const
+{
+ return m_nPrintValues;
+}
diff --git a/tools/lldb-mi/MICmdArgValPrintValues.h b/tools/lldb-mi/MICmdArgValPrintValues.h
new file mode 100644
index 000000000000..37de923e9e52
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValPrintValues.h
@@ -0,0 +1,53 @@
+//===-- MICmdArgValPrintValues.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
+
+// 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. The print-values looks like:
+// 0 or --no-values
+// 1 or --all-values
+// 2 or --simple-values
+// Based on the Interpreter pattern.
+//--
+class CMICmdArgValPrintValues : public CMICmdArgValBaseTemplate<MIuint>
+{
+ // Methods:
+ public:
+ /* ctor */ CMICmdArgValPrintValues(void);
+ /* ctor */ CMICmdArgValPrintValues(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd);
+ //
+ bool IsArgPrintValues(const CMIUtilString &vrTxt) const;
+
+ // Overridden:
+ public:
+ // From CMICmdArgValBase
+ /* dtor */ virtual ~CMICmdArgValPrintValues(void);
+ // From CMICmdArgSet::IArg
+ virtual bool Validate(CMICmdArgContext &vArgContext);
+
+ // Methods:
+ private:
+ bool ExtractPrintValues(const CMIUtilString &vrTxt);
+ MIuint GetPrintValues(void) const;
+
+ // Attributes:
+ private:
+ MIuint m_nPrintValues;
+};
diff --git a/tools/lldb-mi/MICmdArgValString.cpp b/tools/lldb-mi/MICmdArgValString.cpp
index c09eead072d1..c8d32901a4e5 100644
--- a/tools/lldb-mi/MICmdArgValString.cpp
+++ b/tools/lldb-mi/MICmdArgValString.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -46,7 +34,7 @@ CMICmdArgValString::CMICmdArgValString(void)
// Throws: None.
//--
CMICmdArgValString::CMICmdArgValString(const bool vbAnything)
- : m_bHandleQuotedString(false)
+ : m_bHandleQuotedString(vbAnything ? true : false)
, m_bAcceptNumbers(false)
, m_bHandleDirPaths(false)
, m_bHandleAnything(vbAnything)
@@ -56,7 +44,7 @@ CMICmdArgValString::CMICmdArgValString(const bool 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
+// Args: vbHandleQuotes - (R) True = Parse a string surrounded by quotes spaces are not delimiters, 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.
@@ -79,7 +67,7 @@ CMICmdArgValString::CMICmdArgValString(const bool vbHandleQuotes, const bool vbA
// 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
+// vbHandleQuotes - (R) True = Parse a string surrounded by quotes spaces are not delimiters, 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)
@@ -120,10 +108,10 @@ bool
CMICmdArgValString::Validate(CMICmdArgContext &vrwArgContext)
{
if (vrwArgContext.IsEmpty())
- return MIstatus::success;
+ return m_bMandatory ? MIstatus::failure : MIstatus::success;
if (m_bHandleQuotedString)
- return (ValidateQuotedText(vrwArgContext) || ValidateQuotedTextEmbedded(vrwArgContext));
+ return ValidateQuotedText(vrwArgContext);
return ValidateSingleText(vrwArgContext);
}
@@ -140,22 +128,6 @@ CMICmdArgValString::Validate(CMICmdArgContext &vrwArgContext)
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())
@@ -168,7 +140,7 @@ CMICmdArgValString::ValidateSingleText(CMICmdArgContext &vrwArgContext)
if (vrwArgContext.RemoveArg(rArg))
{
m_bValid = true;
- m_argValue = rArg;
+ m_argValue = rArg.StripSlashes();
return MIstatus::success;
}
else
@@ -184,8 +156,7 @@ CMICmdArgValString::ValidateSingleText(CMICmdArgContext &vrwArgContext)
//++ ------------------------------------------------------------------------------------
// 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().
+// between quotes then delimited by the next space.
// Type: Method.
// Args: vrwArgContext - (RW) The command's argument options string.
// Return: MIstatus::success - Functional succeeded.
@@ -195,148 +166,21 @@ CMICmdArgValString::ValidateSingleText(CMICmdArgContext &vrwArgContext)
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)
+ const CMIUtilString::VecString_t vecOptions(vrwArgContext.GetArgs());
+ if (vecOptions.size() == 0)
return MIstatus::failure;
- const MIint nLen = strOptions.length();
- if ((nLen > 5) && ((nPos + 2) == (nPos2 - 2)))
+ const CMIUtilString &rArg(vecOptions[0]);
+ if (!IsStringArg(rArg))
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;
+ m_bFound = true;
- // Extract quoted text
- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 3).c_str();
- if (vrwArgContext.RemoveArg(strQuotedTxt))
+ if (vrwArgContext.RemoveArg(rArg))
{
- m_bFound = true;
m_bValid = true;
- m_argValue = strQuotedTxt;
+ const char cQuote = '"';
+ m_argValue = rArg.Trim(cQuote).StripSlashes();
return MIstatus::success;
}
@@ -373,10 +217,6 @@ CMICmdArgValString::IsStringArg(const CMIUtilString &vrTxt) const
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
@@ -417,20 +257,24 @@ CMICmdArgValString::IsStringArgSingleText(const CMIUtilString &vrTxt) const
bool
CMICmdArgValString::IsStringArgQuotedText(const CMIUtilString &vrTxt) const
{
+ // Accept anything as string word
+ if (m_bHandleAnything)
+ return true;
+
// CODETAG_QUOTEDTEXT_SIMILAR_CODE
- const MIchar cQuote = '"';
- const MIint nPos = vrTxt.find(cQuote);
- if (nPos == (MIint)std::string::npos)
+ const char cQuote = '"';
+ const size_t nPos = vrTxt.find(cQuote);
+ if (nPos == std::string::npos)
return false;
// Is one and only quote at end of the string
- if (nPos == (MIint)(vrTxt.length() - 1))
+ if (nPos == (vrTxt.length() - 1))
return false;
- // Quote must be the first character in the string or be preceeded by a space
+ // Quote must be the first character in the string or be preceded by a space
// Also check for embedded string formating quote
- const MIchar cBckSlash = '\\';
- const MIchar cSpace = ' ';
+ const char cBckSlash = '\\';
+ const char cSpace = ' ';
if ((nPos > 1) && (vrTxt[nPos - 1] == cBckSlash) && (vrTxt[nPos - 2] != cSpace))
{
return false;
@@ -439,8 +283,8 @@ CMICmdArgValString::IsStringArgQuotedText(const CMIUtilString &vrTxt) const
return false;
// Need to find the other quote
- const MIint nPos2 = vrTxt.rfind(cQuote);
- if (nPos2 == (MIint)std::string::npos)
+ const size_t nPos2 = vrTxt.rfind(cQuote);
+ if (nPos2 == std::string::npos)
return false;
// Make sure not same quote, need two quotes
@@ -464,22 +308,22 @@ 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)
+ const char cBckSlash = '\\';
+ const size_t nPos = vrTxt.find(cBckSlash);
+ if (nPos == std::string::npos)
return false;
- // Slash must be the first character in the string or be preceeded by a space
- const MIchar cSpace = ' ';
+ // Slash must be the first character in the string or be preceded by a space
+ const char 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)
+ const size_t nPos2 = vrTxt.rfind(cBckSlash);
+ if (nPos2 == std::string::npos)
return false;
- // Make sure not same back slash, need two slashs
+ // Make sure not same back slash, need two slashes
if (nPos == nPos2)
return MIstatus::failure;
@@ -499,15 +343,15 @@ CMICmdArgValString::IsStringArgQuotedTextEmbedded(const CMIUtilString &vrTxt) co
bool
CMICmdArgValString::IsStringArgQuotedQuotedTextEmbedded(const CMIUtilString &vrTxt) const
{
- const MIint nPos = vrTxt.find("\"\\\"");
- if (nPos == (MIint)std::string::npos)
+ const size_t nPos = vrTxt.find("\"\\\"");
+ if (nPos == std::string::npos)
return false;
- const MIint nPos2 = vrTxt.rfind("\\\"\"");
- if (nPos2 == (MIint)std::string::npos)
+ const size_t nPos2 = vrTxt.rfind("\\\"\"");
+ if (nPos2 == std::string::npos)
return false;
- const MIint nLen = vrTxt.length();
+ const size_t nLen = vrTxt.length();
if ((nLen > 5) && ((nPos + 2) == (nPos2 - 2)))
return false;
diff --git a/tools/lldb-mi/MICmdArgValString.h b/tools/lldb-mi/MICmdArgValString.h
index 58f9ee4f32c3..54051d615919 100644
--- a/tools/lldb-mi/MICmdArgValString.h
+++ b/tools/lldb-mi/MICmdArgValString.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -70,7 +58,7 @@ class CMICmdArgValString : public CMICmdArgValBaseTemplate<CMIUtilString>
// Attribute:
private:
- bool m_bHandleQuotedString; // True = Parse a string surrounded by quotes spaces are not delimitors, false = only text up to next
+ bool m_bHandleQuotedString; // True = Parse a string surrounded by quotes spaces are not delimiters, 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
diff --git a/tools/lldb-mi/MICmdArgValThreadGrp.cpp b/tools/lldb-mi/MICmdArgValThreadGrp.cpp
index 606c615dfca2..c7e663c4721b 100644
--- a/tools/lldb-mi/MICmdArgValThreadGrp.cpp
+++ b/tools/lldb-mi/MICmdArgValThreadGrp.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -74,7 +62,7 @@ bool
CMICmdArgValThreadGrp::Validate(CMICmdArgContext &vwArgContext)
{
if (vwArgContext.IsEmpty())
- return MIstatus::success;
+ return m_bMandatory ? MIstatus::failure : MIstatus::success;
if (vwArgContext.GetNumberArgsPresent() == 1)
{
diff --git a/tools/lldb-mi/MICmdArgValThreadGrp.h b/tools/lldb-mi/MICmdArgValThreadGrp.h
index d82b89ff5017..d361f3a87477 100644
--- a/tools/lldb-mi/MICmdArgValThreadGrp.h
+++ b/tools/lldb-mi/MICmdArgValThreadGrp.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmdBase.cpp b/tools/lldb-mi/MICmdBase.cpp
index d08dcb90f65f..de4fec2ff2ff 100644
--- a/tools/lldb-mi/MICmdBase.cpp
+++ b/tools/lldb-mi/MICmdBase.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdBase.h b/tools/lldb-mi/MICmdBase.h
index c2a8fe030310..7209f4fe5d12 100644
--- a/tools/lldb-mi/MICmdBase.h
+++ b/tools/lldb-mi/MICmdBase.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmdCmd.cpp b/tools/lldb-mi/MICmdCmd.cpp
index 50f651f634f6..fbfc60995c5a 100644
--- a/tools/lldb-mi/MICmdCmd.cpp
+++ b/tools/lldb-mi/MICmdCmd.cpp
@@ -7,18 +7,10 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdCmd.h b/tools/lldb-mi/MICmdCmd.h
index 1fd363084b4a..a360ad6a56af 100644
--- a/tools/lldb-mi/MICmdCmd.h
+++ b/tools/lldb-mi/MICmdCmd.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmd.h
-//
// Overview: CMICmdCmdEnablePrettyPrinting interface.
// CMICmdCmdSource interface.
//
@@ -21,13 +18,6 @@
// 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:
diff --git a/tools/lldb-mi/MICmdCmdBreak.cpp b/tools/lldb-mi/MICmdCmdBreak.cpp
index 9ad7ea3540fd..1b3480984bb5 100644
--- a/tools/lldb-mi/MICmdCmdBreak.cpp
+++ b/tools/lldb-mi/MICmdCmdBreak.cpp
@@ -7,22 +7,12 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -242,7 +232,7 @@ CMICmdCmdBreakInsert::Execute(void)
m_brkPt = sbTarget.BreakpointCreateByLocation(fileName.c_str(), nFileLine);
break;
case eBreakPoint_ByName:
- m_brkPt = sbTarget.BreakpointCreateByName(m_brkName.c_str(), sbTarget.GetExecutable().GetFilename());
+ m_brkPt = sbTarget.BreakpointCreateByName(m_brkName.c_str(), nullptr);
break;
case eBreakPoint_count:
case eBreakPoint_NotDefineYet:
@@ -253,25 +243,33 @@ CMICmdCmdBreakInsert::Execute(void)
if (bOk)
{
+ if (!m_bBrkPtIsPending && (m_brkPt.GetNumLocations() == 0))
+ {
+ sbTarget.BreakpointDelete(m_brkPt.GetID());
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_BRKPT_LOCATION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_brkName.c_str()));
+ return MIstatus::failure;
+ }
+
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;
+ if (!rSessionInfo.GetBrkPtInfo(m_brkPt, sBrkPtInfo))
+ return MIstatus::failure;
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_nTimes = m_brkPt.GetHitCount();
sBrkPtInfo.m_strOrigLoc = m_brkName;
sBrkPtInfo.m_nIgnore = m_nBrkPtIgnoreCount;
sBrkPtInfo.m_bPending = m_bBrkPtIsPending;
@@ -279,8 +277,8 @@ CMICmdCmdBreakInsert::Execute(void)
sBrkPtInfo.m_strCondition = m_brkPtCondition;
sBrkPtInfo.m_bBrkPtThreadId = m_bBrkPtThreadId;
sBrkPtInfo.m_nBrkPtThreadId = m_nBrkPtThreadId;
- bOk = bOk && rSessionInfo.RecordBrkPtInfo(m_brkPt.GetID(), sBrkPtInfo);
+ 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()));
@@ -313,33 +311,14 @@ CMICmdCmdBreakInsert::Acknowledge(void)
// Get breakpoint information
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo;
- if (!rSessionInfo.GetBrkPtInfo(m_brkPt, sBrkPtInfo))
- {
+ if (!rSessionInfo.RecordBrkPtInfoGet(m_brkPt.GetID(), 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.GetHitCount();
- 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\"}"
+ // "^done,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%016" PRIx64 "\",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);
diff --git a/tools/lldb-mi/MICmdCmdBreak.h b/tools/lldb-mi/MICmdCmdBreak.h
index 371afa15b639..06a3434ca5bb 100644
--- a/tools/lldb-mi/MICmdCmdBreak.h
+++ b/tools/lldb-mi/MICmdCmdBreak.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdBreak.h
-//
// Overview: CMICmdCmdBreakInsert interface.
// CMICmdCmdBreakDelete interface.
// CMICmdCmdBreakDisable interface.
@@ -25,13 +22,6 @@
// 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
diff --git a/tools/lldb-mi/MICmdCmdData.cpp b/tools/lldb-mi/MICmdCmdData.cpp
index 92e419073335..bd0209337cd4 100644
--- a/tools/lldb-mi/MICmdCmdData.cpp
+++ b/tools/lldb-mi/MICmdCmdData.cpp
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdData.cpp
-//
// Overview: CMICmdCmdDataEvaluateExpression implementation.
// CMICmdCmdDataDisassemble implementation.
// CMICmdCmdDataReadMemoryBytes implementation.
@@ -19,15 +16,11 @@
// 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.
-//--
+// CMICmdCmdDataInfoLine implementation.
// Third Party Headers:
+#include <inttypes.h> // For PRIx64
+#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBThread.h"
#include "lldb/API/SBInstruction.h"
#include "lldb/API/SBInstructionList.h"
@@ -132,7 +125,7 @@ CMICmdCmdDataEvaluateExpression::Execute(void)
lldb::SBValue value = frame.EvaluateExpression(rExpression.c_str());
if (!value.IsValid() || value.GetError().Fail())
value = frame.FindVariable(rExpression.c_str());
- const CMICmnLLDBUtilSBValue utilValue(value);
+ const CMICmnLLDBUtilSBValue utilValue(value, true);
if (!utilValue.IsValid() || utilValue.IsValueUnknown())
{
m_bEvaluatedExpression = false;
@@ -160,12 +153,7 @@ CMICmdCmdDataEvaluateExpression::Execute(void)
{
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());
- }
+ m_strValue = utilValue.GetValue().Escape().AddSlashes();
return MIstatus::success;
}
@@ -277,7 +265,7 @@ CMICmdCmdDataEvaluateExpression::CreateSelf(void)
// Throws: None.
//--
bool
-CMICmdCmdDataEvaluateExpression::HaveInvalidCharacterInExpression(const CMIUtilString &vrExpr, MIchar &vrwInvalidChar)
+CMICmdCmdDataEvaluateExpression::HaveInvalidCharacterInExpression(const CMIUtilString &vrExpr, char &vrwInvalidChar)
{
static const std::string strInvalidCharacters(";#\\");
const size_t nInvalidCharacterOffset = vrExpr.find_first_of(strInvalidCharacters);
@@ -408,35 +396,44 @@ CMICmdCmdDataDisassemble::Execute(void)
lldb::addr_t lldbStartAddr = static_cast<lldb::addr_t>(nAddrStart);
lldb::SBInstructionList instructions = sbTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, sbTarget), nAddrEnd - nAddrStart);
const MIuint nInstructions = instructions.GetSize();
+ // Calculate the offset of first instruction so that we can generate offset starting at 0
+ lldb::addr_t start_offset = 0;
+ if(nInstructions > 0)
+ start_offset = instructions.GetInstructionAtIndex(0).GetAddress().GetOffset();
+
for (size_t i = 0; i < nInstructions; i++)
{
- const MIchar *pUnknown = "??";
+ const char *pUnknown = "??";
lldb::SBInstruction instrt = instructions.GetInstructionAtIndex(i);
- const MIchar *pStrMnemonic = instrt.GetMnemonic(sbTarget);
+ const char *pStrMnemonic = instrt.GetMnemonic(sbTarget);
pStrMnemonic = (pStrMnemonic != nullptr) ? pStrMnemonic : pUnknown;
+ const char *pStrComment = instrt.GetComment(sbTarget);
+ CMIUtilString strComment;
+ if (pStrComment != nullptr && *pStrComment != '\0')
+ strComment = CMIUtilString::Format("; %s", pStrComment);
lldb::SBAddress address = instrt.GetAddress();
lldb::addr_t addr = address.GetLoadAddress(sbTarget);
- const MIchar *pFnName = address.GetFunction().GetName();
+ const char *pFnName = address.GetFunction().GetName();
pFnName = (pFnName != nullptr) ? pFnName : pUnknown;
- lldb::addr_t addrOffSet = address.GetOffset();
- const MIchar *pStrOperands = instrt.GetOperands(sbTarget);
+ lldb::addr_t addrOffSet = address.GetOffset() - start_offset;
+ const char *pStrOperands = instrt.GetOperands(sbTarget);
pStrOperands = (pStrOperands != nullptr) ? pStrOperands : pUnknown;
const size_t instrtSize = instrt.GetByteSize();
- // MI "{address=\"0x%08llx\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}"
- const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%08llx", addr));
+ // MI "{address=\"0x%016" PRIx64 "\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}"
+ const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%016" PRIx64, 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 CMICmnMIValueConst miValueConst3(CMIUtilString::Format("%lld", addrOffSet));
const CMICmnMIValueResult miValueResult3("offset", miValueConst3);
miValueTuple.Add(miValueResult3);
const CMICmnMIValueConst miValueConst4(CMIUtilString::Format("%d", instrtSize));
const CMICmnMIValueResult miValueResult4("size", miValueConst4);
miValueTuple.Add(miValueResult4);
- const CMICmnMIValueConst miValueConst5(CMIUtilString::Format("%s %s", pStrMnemonic, pStrOperands));
+ const CMICmnMIValueConst miValueConst5(CMIUtilString::Format("%s %s%s", pStrMnemonic, pStrOperands, strComment.Escape(true).c_str()));
const CMICmnMIValueResult miValueResult5("inst", miValueConst5);
miValueTuple.Add(miValueResult5);
@@ -444,7 +441,7 @@ CMICmdCmdDataDisassemble::Execute(void)
{
lldb::SBLineEntry lineEntry = address.GetLineEntry();
const MIuint nLine = lineEntry.GetLine();
- const MIchar *pFileName = lineEntry.GetFileSpec().GetFilename();
+ const char *pFileName = lineEntry.GetFileSpec().GetFilename();
pFileName = (pFileName != nullptr) ? pFileName : pUnknown;
// MI "src_and_asm_line={line=\"%u\",file=\"%s\",line_asm_insn=[ ]}"
@@ -515,13 +512,13 @@ CMICmdCmdDataDisassemble::CreateSelf(void)
//--
CMICmdCmdDataReadMemoryBytes::CMICmdCmdDataReadMemoryBytes(void)
: m_constStrArgThread("thread")
+ , m_constStrArgFrame("frame")
, m_constStrArgByteOffset("o")
- , m_constStrArgAddrStart("address")
+ , m_constStrArgAddrExpr("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";
@@ -559,11 +556,13 @@ bool
CMICmdCmdDataReadMemoryBytes::ParseArgs(void)
{
bool bOk =
- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1)));
+ 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 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 CMICmdArgValString(m_constStrArgAddrExpr, true, true, true, true)));
bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumBytes, true, true)));
return (bOk && ParseValidateCmdOptions());
}
@@ -573,32 +572,101 @@ CMICmdCmdDataReadMemoryBytes::ParseArgs(void)
// 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.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
// Throws: None.
//--
bool
CMICmdCmdDataReadMemoryBytes::Execute(void)
{
- CMICMDBASE_GETOPTION(pArgAddrStart, Number, m_constStrArgAddrStart);
- CMICMDBASE_GETOPTION(pArgAddrOffset, Number, m_constStrArgByteOffset);
+ CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread);
+ CMICMDBASE_GETOPTION(pArgFrame, OptionLong, m_constStrArgFrame);
+ CMICMDBASE_GETOPTION(pArgAddrOffset, OptionShort, m_constStrArgByteOffset);
+ CMICMDBASE_GETOPTION(pArgAddrExpr, String, m_constStrArgAddrExpr);
CMICMDBASE_GETOPTION(pArgNumBytes, Number, m_constStrArgNumBytes);
- const MIuint64 nAddrStart = pArgAddrStart->GetValue();
+ // get the --thread option value
+ MIuint64 nThreadId = UINT64_MAX;
+ if (pArgThread->GetFound() && !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;
+ }
+
+ // get the --frame option value
+ MIuint64 nFrame = UINT64_MAX;
+ if (pArgFrame->GetFound() && !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;
+ }
+
+ // get the -o option value
+ MIuint64 nAddrOffset = 0;
+ if (pArgAddrOffset->GetFound() && !pArgAddrOffset->GetExpectedOption<CMICmdArgValNumber, MIuint64>(nAddrOffset))
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND),
+ m_cmdData.strMiCmd.c_str(), m_constStrArgByteOffset.c_str()));
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
+ if (!sbProcess.IsValid())
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str()));
+ return MIstatus::failure;
+ }
+
+ lldb::SBThread thread = (nThreadId != UINT64_MAX) ?
+ sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread();
+ if (!thread.IsValid())
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str()));
+ return MIstatus::failure;
+ }
+
+ lldb::SBFrame frame = (nFrame != UINT64_MAX) ?
+ thread.GetFrameAtIndex(nFrame) : thread.GetSelectedFrame();
+ if (!frame.IsValid())
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FRAME_INVALID), m_cmdData.strMiCmd.c_str()));
+ return MIstatus::failure;
+ }
+
+ const CMIUtilString &rAddrExpr = pArgAddrExpr->GetValue();
+ lldb::SBValue addrExprValue = frame.EvaluateExpression(rAddrExpr.c_str());
+ lldb::SBError error = addrExprValue.GetError();
+ if (error.Fail())
+ {
+ SetError(error.GetCString());
+ return MIstatus::failure;
+ }
+ else if (!addrExprValue.IsValid())
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_EXPR_INVALID), rAddrExpr.c_str()));
+ return MIstatus::failure;
+ }
+
+ MIuint64 nAddrStart = 0;
+ if (!CMICmnLLDBProxySBValue::GetValueAsUnsigned(addrExprValue, nAddrStart))
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_EXPR_INVALID), rAddrExpr.c_str()));
+ return MIstatus::failure;
+ }
+
+ nAddrStart += nAddrOffset;
const MIuint64 nAddrNumBytes = pArgNumBytes->GetValue();
- if (pArgAddrOffset->GetFound())
- m_nAddrOffset = pArgAddrOffset->GetValue();
- m_pBufferMemory = new MIuchar[nAddrNumBytes];
+ m_pBufferMemory = new unsigned char[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 sbProcess = rSessionInfo.GetProcess();
- lldb::SBError error;
const MIuint64 nReadBytes = sbProcess.ReadMemory(static_cast<lldb::addr_t>(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error);
if (nReadBytes != nAddrNumBytes)
{
@@ -634,14 +702,15 @@ CMICmdCmdDataReadMemoryBytes::Execute(void)
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));
+ // MI: memory=[{begin=\"0x%016" PRIx64 "\",offset=\"0x%016" PRIx64" \",end=\"0x%016" PRIx64 "\",contents=\" \" }]"
+ const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%016" PRIx64, m_nAddrStart));
const CMICmnMIValueResult miValueResult("begin", miValueConst);
CMICmnMIValueTuple miValueTuple(miValueResult);
- const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("0x%08x", m_nAddrOffset));
+ const MIuint64 nAddrOffset = 0;
+ const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("0x%016" PRIx64, nAddrOffset));
const CMICmnMIValueResult miValueResult2("offset", miValueConst2);
miValueTuple.Add(miValueResult2);
- const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("0x%08x", m_nAddrStart + m_nAddrNumBytesToRead));
+ const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("0x%016" PRIx64, m_nAddrStart + m_nAddrNumBytesToRead));
const CMICmnMIValueResult miValueResult3("end", miValueConst3);
miValueTuple.Add(miValueResult3);
@@ -650,7 +719,7 @@ CMICmdCmdDataReadMemoryBytes::Acknowledge(void)
strContent.reserve((m_nAddrNumBytesToRead << 1) + 1);
for (MIuint64 i = 0; i < m_nAddrNumBytesToRead; i++)
{
- strContent += CMIUtilString::Format("%02x", m_pBufferMemory[i]);
+ strContent += CMIUtilString::Format("%02hhx", m_pBufferMemory[i]);
}
const CMICmnMIValueConst miValueConst4(strContent);
const CMICmnMIValueResult miValueResult4("contents", miValueConst4);
@@ -1475,13 +1544,13 @@ CMICmdCmdDataWriteMemory::Execute(void)
m_nCount = pArgNumber->GetValue();
const MIuint64 nValue = pArgContents->GetValue();
- m_pBufferMemory = new MIuchar[m_nCount];
+ m_pBufferMemory = new unsigned char[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);
+ *m_pBufferMemory = static_cast<char>(nValue);
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
@@ -1537,3 +1606,224 @@ CMICmdCmdDataWriteMemory::CreateSelf(void)
{
return new CMICmdCmdDataWriteMemory();
}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataInfoLine constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataInfoLine::CMICmdCmdDataInfoLine(void)
+ : m_constStrArgLocation("location")
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "data-info-line";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdDataInfoLine::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataInfoLine destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataInfoLine::~CMICmdCmdDataInfoLine(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
+CMICmdCmdDataInfoLine::ParseArgs(void)
+{
+ bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValString(m_constStrArgLocation, 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
+CMICmdCmdDataInfoLine::Execute(void)
+{
+ CMICMDBASE_GETOPTION(pArgLocation, String, m_constStrArgLocation);
+
+ const CMIUtilString &strLocation(pArgLocation->GetValue());
+ CMIUtilString strCmdOptionsLocation;
+ if (strLocation.at(0) == '*')
+ {
+ // Parse argument:
+ // *0x12345
+ // ^^^^^^^ -- address
+ const CMIUtilString strAddress(strLocation.c_str() + 1);
+ strCmdOptionsLocation = CMIUtilString::Format("--address %s", strAddress.c_str());
+ }
+ else
+ {
+ const size_t nLineStartPos = strLocation.rfind(':');
+ if ((nLineStartPos == std::string::npos) || (nLineStartPos == 0) || (nLineStartPos == strLocation.length() - 1))
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_LOCATION_FORMAT), m_cmdData.strMiCmd.c_str(), strLocation.c_str())
+ .c_str());
+ return MIstatus::failure;
+ }
+ // Parse argument:
+ // hello.cpp:5
+ // ^^^^^^^^^ -- file
+ // ^ -- line
+ const CMIUtilString strFile(strLocation.substr(0, nLineStartPos).c_str());
+ const CMIUtilString strLine(strLocation.substr(nLineStartPos + 1).c_str());
+ strCmdOptionsLocation = CMIUtilString::Format("--file \"%s\" --line %s", strFile.AddSlashes().c_str(), strLine.c_str());
+ }
+ const CMIUtilString strCmd(CMIUtilString::Format("target modules lookup -v %s", strCmdOptionsLocation.c_str()));
+
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult);
+ 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
+CMICmdCmdDataInfoLine::Acknowledge(void)
+{
+ if (m_lldbResult.GetErrorSize() > 0)
+ {
+ const CMICmnMIValueConst miValueConst(m_lldbResult.GetError());
+ const CMICmnMIValueResult miValueResult("msg", miValueConst);
+ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+ else if (m_lldbResult.GetOutputSize() > 0)
+ {
+ CMIUtilString::VecString_t vecLines;
+ const CMIUtilString strLldbMsg(m_lldbResult.GetOutput());
+ const MIuint nLines(strLldbMsg.SplitLines(vecLines));
+
+ for (MIuint i = 0; i < nLines; ++i)
+ {
+ // String looks like:
+ // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
+ const CMIUtilString &rLine(vecLines[i]);
+
+ // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
+ // ^^^^^^^^^ -- property
+ const size_t nPropertyStartPos = rLine.find_first_not_of(' ');
+ const size_t nPropertyEndPos = rLine.find(':');
+ const size_t nPropertyLen = nPropertyEndPos - nPropertyStartPos;
+ const CMIUtilString strProperty(rLine.substr(nPropertyStartPos, nPropertyLen).c_str());
+
+ // Skip all except LineEntry
+ if (!CMIUtilString::Compare(strProperty, "LineEntry"))
+ continue;
+
+ // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
+ // ^^^^^^^^^^^^^^^^^^ -- start address
+ const size_t nStartAddressStartPos = rLine.find("[");
+ const size_t nStartAddressEndPos = rLine.find("-");
+ const size_t nStartAddressLen = nStartAddressEndPos - nStartAddressStartPos - 1;
+ const CMIUtilString strStartAddress(rLine.substr(nStartAddressStartPos + 1, nStartAddressLen).c_str());
+ const CMICmnMIValueConst miValueConst(strStartAddress);
+ const CMICmnMIValueResult miValueResult("start", miValueConst);
+ CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
+
+ // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
+ // ^^^^^^^^^^^^^^^^^^ -- end address
+ const size_t nEndAddressEndPos = rLine.find(")");
+ const size_t nEndAddressLen = nEndAddressEndPos - nStartAddressEndPos - 1;
+ const CMIUtilString strEndAddress(rLine.substr(nStartAddressEndPos + 1, nEndAddressLen).c_str());
+ const CMICmnMIValueConst miValueConst2(strEndAddress);
+ const CMICmnMIValueResult miValueResult2("end", miValueConst2);
+ bool bOk = miRecordResult.Add(miValueResult2);
+ if (!bOk)
+ return MIstatus::failure;
+
+ // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
+ // ^^^^^^^^^^^^^ -- file
+ // ^ -- line
+ // ^ -- column (optional)
+ const size_t nFileStartPos = rLine.find_first_not_of(' ', nEndAddressEndPos + 2);
+ const size_t nFileOrLineEndPos = rLine.rfind(':');
+ const size_t nFileOrLineStartPos = rLine.rfind(':', nFileOrLineEndPos - 1);
+ const size_t nFileEndPos = nFileStartPos < nFileOrLineStartPos ? nFileOrLineStartPos : nFileOrLineEndPos;
+ const size_t nFileLen = nFileEndPos - nFileStartPos;
+ const CMIUtilString strFile(rLine.substr(nFileStartPos, nFileLen).c_str());
+ const CMICmnMIValueConst miValueConst3(strFile);
+ const CMICmnMIValueResult miValueResult3("file", miValueConst3);
+ bOk = miRecordResult.Add(miValueResult3);
+ if (!bOk)
+ return MIstatus::failure;
+
+ // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
+ // ^ -- line
+ const size_t nLineStartPos = nFileEndPos + 1;
+ const size_t nLineEndPos = rLine.find(':', nLineStartPos);
+ const size_t nLineLen = nLineEndPos != std::string::npos ? nLineEndPos - nLineStartPos - 1
+ : std::string::npos;
+ const CMIUtilString strLine(rLine.substr(nLineStartPos, nLineLen).c_str());
+ const CMICmnMIValueConst miValueConst4(strLine);
+ const CMICmnMIValueResult miValueResult4("line", miValueConst4);
+ bOk = miRecordResult.Add(miValueResult4);
+ if (!bOk)
+ return MIstatus::failure;
+
+ // MI print "%s^done,start=\"%d\",end=\"%d\"",file=\"%s\",line=\"%d\"
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+ }
+ }
+
+ // MI print "%s^error,msg=\"Command '-data-info-line'. Error: The LineEntry is absent or has an unknown format.\""
+ const CMICmnMIValueConst miValueConst(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_SOME_ERROR), m_cmdData.strMiCmd.c_str(), "The LineEntry is absent or has an unknown format."));
+ 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 *
+CMICmdCmdDataInfoLine::CreateSelf(void)
+{
+ return new CMICmdCmdDataInfoLine();
+}
diff --git a/tools/lldb-mi/MICmdCmdData.h b/tools/lldb-mi/MICmdCmdData.h
index 5084beea6d8f..11873e9cbe4f 100644
--- a/tools/lldb-mi/MICmdCmdData.h
+++ b/tools/lldb-mi/MICmdCmdData.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdData.h
-//
// Overview: CMICmdCmdDataEvaluateExpression interface.
// CMICmdCmdDataDisassemble interface.
// CMICmdCmdDataReadMemoryBytes interface.
@@ -19,6 +16,7 @@
// CMICmdCmdDataListRegisterChanged interface.
// CMICmdCmdDataWriteMemoryBytes interface.
// CMICmdCmdDataWriteMemory interface.
+// CMICmdCmdDataInfoLine 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
@@ -29,15 +27,12 @@
// 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"
@@ -73,7 +68,7 @@ class CMICmdCmdDataEvaluateExpression : public CMICmdBase
// Methods:
private:
- bool HaveInvalidCharacterInExpression(const CMIUtilString &vrExpr, MIchar &vrwInvalidChar);
+ bool HaveInvalidCharacterInExpression(const CMIUtilString &vrExpr, char &vrwInvalidChar);
// Attributes:
private:
@@ -83,7 +78,7 @@ class CMICmdCmdDataEvaluateExpression : public CMICmdBase
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;
+ char 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;
@@ -155,14 +150,14 @@ class CMICmdCmdDataReadMemoryBytes : public CMICmdBase
// Attributes:
private:
- const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command.
+ const CMIUtilString m_constStrArgThread; // Not in the MI spec but implemented by GDB.
+ const CMIUtilString m_constStrArgFrame; // Not in the MI spec but implemented by GDB.
const CMIUtilString m_constStrArgByteOffset;
- const CMIUtilString m_constStrArgAddrStart;
+ const CMIUtilString m_constStrArgAddrExpr;
const CMIUtilString m_constStrArgNumBytes;
- MIuchar *m_pBufferMemory;
+ unsigned char *m_pBufferMemory;
MIuint64 m_nAddrStart;
MIuint64 m_nAddrNumBytesToRead;
- MIuint64 m_nAddrOffset;
};
//++ ============================================================================
@@ -373,5 +368,36 @@ class CMICmdCmdDataWriteMemory : public CMICmdBase
MIuint64 m_nAddr;
CMIUtilString m_strContents;
MIuint64 m_nCount;
- MIuchar *m_pBufferMemory;
+ unsigned char *m_pBufferMemory;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "data-info-line".
+// See MIExtensions.txt for details.
+//--
+class CMICmdCmdDataInfoLine : public CMICmdBase
+{
+ // Statics:
+ public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase *CreateSelf(void);
+
+ // Methods:
+ public:
+ /* ctor */ CMICmdCmdDataInfoLine(void);
+
+ // Overridden:
+ public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute(void);
+ virtual bool Acknowledge(void);
+ virtual bool ParseArgs(void);
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdDataInfoLine(void);
+
+ // Attributes:
+ private:
+ lldb::SBCommandReturnObject m_lldbResult;
+ const CMIUtilString m_constStrArgLocation;
};
diff --git a/tools/lldb-mi/MICmdCmdEnviro.cpp b/tools/lldb-mi/MICmdCmdEnviro.cpp
index a4369ab3a990..dd167841032a 100644
--- a/tools/lldb-mi/MICmdCmdEnviro.cpp
+++ b/tools/lldb-mi/MICmdCmdEnviro.cpp
@@ -7,17 +7,7 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdCmdEnviro.h b/tools/lldb-mi/MICmdCmdEnviro.h
index 9a223beb91b0..1fb699e989b6 100644
--- a/tools/lldb-mi/MICmdCmdEnviro.h
+++ b/tools/lldb-mi/MICmdCmdEnviro.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdEnviro.h
-//
// Overview: CMICmdCmdEnvironmentCd interface.
//
// To implement new MI commands derive a new command class from the command base
@@ -20,13 +17,6 @@
// 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
diff --git a/tools/lldb-mi/MICmdCmdExec.cpp b/tools/lldb-mi/MICmdCmdExec.cpp
index eec62c8d37e8..f0208c83d58d 100644
--- a/tools/lldb-mi/MICmdCmdExec.cpp
+++ b/tools/lldb-mi/MICmdCmdExec.cpp
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdExec.cpp
-//
// Overview: CMICmdCmdExecRun implementation.
// CMICmdCmdExecContinue implementation.
// CMICmdCmdExecNext implementation.
@@ -18,13 +15,8 @@
// 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.
-//--
+// CMICmdCmdExecArguments implementation.
+// CMICmdCmdExecAbort implementation.
// Third Party Headers:
#include "lldb/API/SBCommandInterpreter.h"
@@ -90,10 +82,9 @@ CMICmdCmdExecRun::Execute(void)
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
lldb::SBError error;
lldb::SBStream errMsg;
- uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug;
- lldb::SBProcess process = rSessionInfo.GetTarget().Launch(rSessionInfo.GetListener(), nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, launch_flags, false, error);
-
+ lldb::SBLaunchInfo launchInfo = rSessionInfo.GetTarget().GetLaunchInfo();
+ launchInfo.SetListener(rSessionInfo.GetListener());
+ lldb::SBProcess process = rSessionInfo.GetTarget().Launch(launchInfo, error);
if ((!process.IsValid()) || (error.Fail()))
{
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str(), errMsg.GetData()));
@@ -207,7 +198,7 @@ CMICmdCmdExecContinue::~CMICmdCmdExecContinue(void)
bool
CMICmdCmdExecContinue::Execute(void)
{
- const MIchar *pCmd = "continue";
+ const char *pCmd = "continue";
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(pCmd, m_lldbResult);
MIunused(rtn);
@@ -226,7 +217,7 @@ CMICmdCmdExecContinue::Execute(void)
{
// 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 char *pLldbErr = m_lldbResult.GetError();
const CMIUtilString strLldbMsg(CMIUtilString(pLldbErr).StripCREndOfLine());
if (strLldbMsg == "error: Process must be launched.")
{
@@ -376,7 +367,7 @@ CMICmdCmdExecNext::Acknowledge(void)
{
if (m_lldbResult.GetErrorSize() > 0)
{
- const MIchar *pLldbErr = m_lldbResult.GetError();
+ const char *pLldbErr = m_lldbResult.GetError();
MIunused(pLldbErr);
const CMICmnMIValueConst miValueConst(m_lldbResult.GetError());
const CMICmnMIValueResult miValueResult("message", miValueConst);
@@ -503,7 +494,7 @@ CMICmdCmdExecStep::Acknowledge(void)
{
if (m_lldbResult.GetErrorSize() > 0)
{
- const MIchar *pLldbErr = m_lldbResult.GetError();
+ const char *pLldbErr = m_lldbResult.GetError();
MIunused(pLldbErr);
const CMICmnMIValueConst miValueConst(m_lldbResult.GetError());
const CMICmnMIValueResult miValueResult("message", miValueConst);
@@ -630,7 +621,7 @@ CMICmdCmdExecNextInstruction::Acknowledge(void)
{
if (m_lldbResult.GetErrorSize() > 0)
{
- const MIchar *pLldbErr = m_lldbResult.GetError();
+ const char *pLldbErr = m_lldbResult.GetError();
MIunused(pLldbErr);
const CMICmnMIValueConst miValueConst(m_lldbResult.GetError());
const CMICmnMIValueResult miValueResult("message", miValueConst);
@@ -757,7 +748,7 @@ CMICmdCmdExecStepInstruction::Acknowledge(void)
{
if (m_lldbResult.GetErrorSize() > 0)
{
- const MIchar *pLldbErr = m_lldbResult.GetError();
+ const char *pLldbErr = m_lldbResult.GetError();
MIunused(pLldbErr);
const CMICmnMIValueConst miValueConst(m_lldbResult.GetError());
const CMICmnMIValueResult miValueResult("message", miValueConst);
@@ -885,7 +876,7 @@ CMICmdCmdExecFinish::Acknowledge(void)
{
if (m_lldbResult.GetErrorSize() > 0)
{
- const MIchar *pLldbErr = m_lldbResult.GetError();
+ const char *pLldbErr = m_lldbResult.GetError();
MIunused(pLldbErr);
const CMICmnMIValueConst miValueConst(m_lldbResult.GetError());
const CMICmnMIValueResult miValueResult("message", miValueConst);
@@ -1016,3 +1007,215 @@ CMICmdCmdExecInterrupt::CreateSelf(void)
{
return new CMICmdCmdExecInterrupt();
}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecArguments constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecArguments::CMICmdCmdExecArguments(void)
+ : m_constStrArgArguments("arguments")
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "exec-arguments";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdExecArguments::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecArguments destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecArguments::~CMICmdCmdExecArguments(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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdExecArguments::ParseArgs(void)
+{
+ bool bOk = m_setCmdArgs.Add(
+ *(new CMICmdArgValListOfN(m_constStrArgArguments, false, 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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdExecArguments::Execute(void)
+{
+ CMICMDBASE_GETOPTION(pArgArguments, ListOfN, m_constStrArgArguments);
+
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ lldb::SBTarget sbTarget = rSessionInfo.GetTarget();
+ if (!sbTarget.IsValid())
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT), m_cmdData.strMiCmd.c_str()));
+ return MIstatus::failure;
+ }
+
+ lldb::SBLaunchInfo sbLaunchInfo = sbTarget.GetLaunchInfo();
+ sbLaunchInfo.SetArguments(NULL, false);
+
+ CMIUtilString strArg;
+ size_t nArgIndex = 0;
+ while (pArgArguments->GetExpectedOption<CMICmdArgValString, CMIUtilString>(strArg, nArgIndex))
+ {
+ const char *argv[2] = { strArg.c_str(), NULL };
+ sbLaunchInfo.SetArguments(argv, true);
+ ++nArgIndex;
+ }
+
+ sbTarget.SetLaunchInfo(sbLaunchInfo);
+
+ 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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdExecArguments::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 *
+CMICmdCmdExecArguments::CreateSelf(void)
+{
+ return new CMICmdCmdExecArguments();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecAbort constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecAbort::CMICmdCmdExecAbort(void)
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "exec-abort";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdExecAbort::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecAbort destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecAbort::~CMICmdCmdExecAbort(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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdExecAbort::Execute(void)
+{
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
+ if (!sbProcess.IsValid())
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str()));
+ return MIstatus::failure;
+ }
+
+ lldb::SBError sbError = sbProcess.Destroy();
+ if (sbError.Fail())
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDBPROCESS_DESTROY), m_cmdData.strMiCmd.c_str(), sbError.GetCString()));
+ 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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdExecAbort::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 *
+CMICmdCmdExecAbort::CreateSelf(void)
+{
+ return new CMICmdCmdExecAbort();
+}
diff --git a/tools/lldb-mi/MICmdCmdExec.h b/tools/lldb-mi/MICmdCmdExec.h
index be03d6b93566..8889fb96402e 100644
--- a/tools/lldb-mi/MICmdCmdExec.h
+++ b/tools/lldb-mi/MICmdCmdExec.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdExec.h
-//
// Overview: CMICmdCmdExecRun interface.
// CMICmdCmdExecContinue interface.
// CMICmdCmdExecNext interface.
@@ -18,6 +15,8 @@
// CMICmdCmdExecStepInstruction interface.
// CMICmdCmdExecFinish interface.
// CMICmdCmdExecInterrupt interface.
+// CMICmdCmdExecArguments interface.
+// CMICmdCmdExecAbort 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
@@ -27,13 +26,6 @@
// 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
@@ -307,3 +299,59 @@ class CMICmdCmdExecInterrupt : public CMICmdBase
private:
lldb::SBCommandReturnObject m_lldbResult;
};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "exec-arguments".
+// Gotchas: None.
+// Authors: Ilia Kirianovskii 25/11/2014.
+// Changes: None.
+//--
+class CMICmdCmdExecArguments : public CMICmdBase
+{
+ // Statics:
+ public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase *CreateSelf(void);
+
+ // Methods:
+ public:
+ /* ctor */ CMICmdCmdExecArguments(void);
+
+ // Overridden:
+ public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute(void);
+ virtual bool Acknowledge(void);
+ virtual bool ParseArgs(void);
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdExecArguments(void);
+
+ // Attributes:
+ private:
+ const CMIUtilString m_constStrArgArguments;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "exec-abort".
+//--
+class CMICmdCmdExecAbort : public CMICmdBase
+{
+ // Statics:
+ public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase *CreateSelf(void);
+
+ // Methods:
+ public:
+ /* ctor */ CMICmdCmdExecAbort(void);
+
+ // Overridden:
+ public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute(void);
+ virtual bool Acknowledge(void);
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdExecAbort(void);
+};
diff --git a/tools/lldb-mi/MICmdCmdFile.cpp b/tools/lldb-mi/MICmdCmdFile.cpp
index 83862f24f1f1..b28060e29f25 100644
--- a/tools/lldb-mi/MICmdCmdFile.cpp
+++ b/tools/lldb-mi/MICmdCmdFile.cpp
@@ -7,17 +7,7 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -29,7 +19,9 @@
#include "MICmnLLDBDebugSessionInfo.h"
#include "MIUtilFileStd.h"
#include "MICmdArgValFile.h"
+#include "MICmdArgValString.h"
#include "MICmdArgValOptionLong.h"
+#include "MICmdArgValOptionShort.h"
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdFileExecAndSymbols constructor.
@@ -41,6 +33,8 @@
CMICmdCmdFileExecAndSymbols::CMICmdCmdFileExecAndSymbols(void)
: m_constStrArgNameFile("file")
, m_constStrArgThreadGrp("thread-group")
+ , m_constStrArgNamedPlatformName("p")
+ , m_constStrArgNamedRemotePath("r")
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "file-exec-and-symbols";
@@ -75,6 +69,12 @@ 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)));
+ bOk = bOk &&
+ m_setCmdArgs.Add(*(new CMICmdArgValOptionShort(m_constStrArgNamedPlatformName, false, true,
+ CMICmdArgValListBase::eArgValType_String, 1)));
+ bOk = bOk &&
+ m_setCmdArgs.Add(*(new CMICmdArgValOptionShort(m_constStrArgNamedRemotePath, false, true,
+ CMICmdArgValListBase::eArgValType_StringQuotedNumberPath, 1)));
return (bOk && ParseValidateCmdOptions());
}
@@ -93,20 +93,28 @@ bool
CMICmdCmdFileExecAndSymbols::Execute(void)
{
CMICMDBASE_GETOPTION(pArgNamedFile, File, m_constStrArgNameFile);
+ CMICMDBASE_GETOPTION(pArgPlatformName, OptionShort, m_constStrArgNamedPlatformName);
+ CMICMDBASE_GETOPTION(pArgRemotePath, OptionShort, m_constStrArgNamedRemotePath);
CMICmdArgValFile *pArgFile = static_cast<CMICmdArgValFile *>(pArgNamedFile);
const CMIUtilString &strExeFilePath(pArgFile->GetValue());
+ bool bPlatformName = pArgPlatformName->GetFound();
+ CMIUtilString platformName;
+ if (bPlatformName)
+ {
+ pArgPlatformName->GetExpectedOption<CMICmdArgValString, CMIUtilString>(platformName);
+ }
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger();
lldb::SBError error;
- const MIchar *pTargetTriple = nullptr; // Let LLDB discover the triple required
- const MIchar *pTargetPlatformName = "";
+ const char *pTargetTriple = nullptr; // Let LLDB discover the triple required
+ const char *pTargetPlatformName = platformName.c_str();
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);
+ 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()));
@@ -119,6 +127,16 @@ CMICmdCmdFileExecAndSymbols::Execute(void)
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FNFAILED), m_cmdData.strMiCmd.c_str(), "SetCurrentPlatformSDKRoot()"));
return MIstatus::failure;
}
+ if (pArgRemotePath->GetFound())
+ {
+ CMIUtilString remotePath;
+ pArgRemotePath->GetExpectedOption<CMICmdArgValString, CMIUtilString>(remotePath);
+ lldb::SBModule module = target.FindModule(target.GetExecutable());
+ if (module.IsValid())
+ {
+ module.SetPlatformFileSpec(lldb::SBFileSpec(remotePath.c_str()));
+ }
+ }
lldb::SBStream err;
if (error.Fail())
{
diff --git a/tools/lldb-mi/MICmdCmdFile.h b/tools/lldb-mi/MICmdCmdFile.h
index 5e23c85daeff..307f4f887aa5 100644
--- a/tools/lldb-mi/MICmdCmdFile.h
+++ b/tools/lldb-mi/MICmdCmdFile.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdFile.h
-//
// Overview: CMICmdCmdFileExecAndSymbols interface.
//
// To implement new MI commands derive a new command class from the command base
@@ -20,13 +17,6 @@
// 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
@@ -39,7 +29,8 @@
// 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.
+// Gotchas: This command has additonal flags that were not available in GDB MI.
+// See MIextensions.txt for details.
// Authors: Illya Rudkin 25/02/2014.
// Changes: None.
//--
@@ -69,4 +60,6 @@ class CMICmdCmdFileExecAndSymbols : public CMICmdBase
const CMIUtilString m_constStrArgNameFile;
const CMIUtilString
m_constStrArgThreadGrp; // Not handled by *this command. Not specified in MI spec but Eclipse gives this option sometimes
+ const CMIUtilString m_constStrArgNamedPlatformName; // Added to support iOS platform selection
+ const CMIUtilString m_constStrArgNamedRemotePath; // Added to support iOS device remote file location
};
diff --git a/tools/lldb-mi/MICmdCmdGdbInfo.cpp b/tools/lldb-mi/MICmdCmdGdbInfo.cpp
index be70962b63ae..25e0ff4ffbe8 100644
--- a/tools/lldb-mi/MICmdCmdGdbInfo.cpp
+++ b/tools/lldb-mi/MICmdCmdGdbInfo.cpp
@@ -7,19 +7,10 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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 <inttypes.h> // For PRIx64
#include "lldb/API/SBCommandReturnObject.h"
// In-house headers:
@@ -209,7 +200,7 @@ CMICmdCmdGdbInfo::PrintFnSharedLibrary(void)
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 addrLoadS = 0xffffffffffffffff;
lldb::addr_t addrLoadSize = 0;
bool bHaveAddrLoad = false;
const MIuint nSections = module.GetNumSections();
@@ -229,7 +220,7 @@ CMICmdCmdGdbInfo::PrintFnSharedLibrary(void)
}
}
bOk = bOk &&
- rStdout.TextToStdout(CMIUtilString::Format("~\"0x%08x\t0x%08x\t%s\t\t%s\"", addrLoadS, addrLoadS + addrLoadSize,
+ rStdout.TextToStdout(CMIUtilString::Format("~\"0x%016" PRIx64 "\t0x%016" PRIx64 "\t%s\t\t%s\"", addrLoadS, addrLoadS + addrLoadSize,
strHasSymbols.c_str(), strModuleFullPath.c_str()));
}
}
diff --git a/tools/lldb-mi/MICmdCmdGdbInfo.h b/tools/lldb-mi/MICmdCmdGdbInfo.h
index 0d45e6c39335..eb60f8277c01 100644
--- a/tools/lldb-mi/MICmdCmdGdbInfo.h
+++ b/tools/lldb-mi/MICmdCmdGdbInfo.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdGdbInfo.h
-//
// Overview: CMICmdCmdGdbInfo interface.
//
// To implement new MI commands derive a new command class from the command base
@@ -20,13 +17,6 @@
// 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
diff --git a/tools/lldb-mi/MICmdCmdGdbSet.cpp b/tools/lldb-mi/MICmdCmdGdbSet.cpp
index c1c1bb599fdd..452ac516f2e4 100644
--- a/tools/lldb-mi/MICmdCmdGdbSet.cpp
+++ b/tools/lldb-mi/MICmdCmdGdbSet.cpp
@@ -1,4 +1,4 @@
-//===-- MICmdCmdGdbSet.cpp ------- -------------------------*- C++ -*-===//
+//===-- MICmdCmdGdbSet.cpp --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,17 +7,7 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -30,8 +20,10 @@
// Instantiations:
const CMICmdCmdGdbSet::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbSet::ms_mapGdbOptionNameToFnGdbOptionPtr = {
- // { "target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync }, // Example code if need to implement GDB set other options
+ {"target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync},
+ {"print", &CMICmdCmdGdbSet::OptionFnPrint},
// { "auto-solib-add", &CMICmdCmdGdbSet::OptionFnAutoSolibAdd }, // Example code if need to implement GDB set other options
+ {"output-radix", &CMICmdCmdGdbSet::OptionFnOutputRadix},
{"solib-search-path", &CMICmdCmdGdbSet::OptionFnSolibSearchPath},
{"fallback", &CMICmdCmdGdbSet::OptionFnFallback}};
@@ -89,7 +81,7 @@ CMICmdCmdGdbSet::ParseArgs(void)
}
//++ ------------------------------------------------------------------------------------
-// Details: The invoker requires this function. The command does work in this function.
+// Details: The invoker requires this function. The command is executed in this function.
// The command is likely to communicate with the LLDB SBDebugger in here.
// Type: Overridden.
// Args: None.
@@ -103,7 +95,8 @@ CMICmdCmdGdbSet::Execute(void)
CMICMDBASE_GETOPTION(pArgGdbOption, ListOfN, m_constStrArgNamedGdbOption);
const CMICmdArgValListBase::VecArgObjPtr_t &rVecWords(pArgGdbOption->GetExpectedOptions());
- // Get the gdb-set option to carry out
+ // Get the gdb-set option to carry out. This option will be used as an action
+ // which should be done. Further arguments will be used as parameters for it.
CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecWords.begin();
const CMICmdArgValString *pOption = static_cast<const CMICmdArgValString *>(*it);
const CMIUtilString strOption(pOption->GetValue());
@@ -142,7 +135,7 @@ CMICmdCmdGdbSet::Execute(void)
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
-// for the work carried out in the Execute().
+// for the work carried out in the Execute() method.
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
@@ -152,6 +145,8 @@ CMICmdCmdGdbSet::Execute(void)
bool
CMICmdCmdGdbSet::Acknowledge(void)
{
+ // Print error if option isn't recognized:
+ // ^error,msg="The request '%s' was not recognized, not implemented"
if (!m_bGdbOptionRecognised)
{
const CMICmnMIValueConst miValueConst(
@@ -162,6 +157,7 @@ CMICmdCmdGdbSet::Acknowledge(void)
return MIstatus::success;
}
+ // ^done,value="%s"
if (m_bGdbOptionFnSuccessful)
{
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
@@ -169,6 +165,8 @@ CMICmdCmdGdbSet::Acknowledge(void)
return MIstatus::success;
}
+ // Print error if request failed:
+ // ^error,msg="The request '%s' failed.
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);
@@ -215,6 +213,98 @@ CMICmdCmdGdbSet::GetOptionFn(const CMIUtilString &vrPrintFnName, FnGdbOptionPtr
}
//++ ------------------------------------------------------------------------------------
+// Details: Carry out work to complete the GDB set option 'target-async' to prepare
+// and send back information asked for.
+// Type: Method.
+// Args: vrWords - (R) List of additional parameters used by this option.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdGdbSet::OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords)
+{
+ bool bAsyncMode = false;
+ bool bOk = true;
+
+ if (vrWords.size() > 1)
+ // Too many arguments.
+ bOk = false;
+ else if (vrWords.size() == 0)
+ // If no arguments, default is "on".
+ bAsyncMode = true;
+ else if (CMIUtilString::Compare(vrWords[0], "on"))
+ bAsyncMode = true;
+ else if (CMIUtilString::Compare(vrWords[0], "off"))
+ bAsyncMode = false;
+ else
+ // Unrecognized argument.
+ bOk = false;
+
+ if (!bOk)
+ {
+ // Report error.
+ m_bGbbOptionFnHasError = true;
+ m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC);
+ return MIstatus::failure;
+ }
+
+ // Turn async mode on/off.
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ rSessionInfo.GetDebugger().SetAsync(bAsyncMode);
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Carry out work to complete the GDB set option 'print-char-array-as-string' to
+// prepare and send back information asked for.
+// Type: Method.
+// Args: vrWords - (R) List of additional parameters used by this option.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdGdbSet::OptionFnPrint(const CMIUtilString::VecString_t &vrWords)
+{
+ const bool bAllArgs(vrWords.size() == 2);
+ const bool bArgOn(bAllArgs && (CMIUtilString::Compare(vrWords[1], "on") || CMIUtilString::Compare(vrWords[1], "1")));
+ const bool bArgOff(bAllArgs && (CMIUtilString::Compare(vrWords[1], "off") || CMIUtilString::Compare(vrWords[1], "0")));
+ if (!bAllArgs || (!bArgOn && !bArgOff))
+ {
+ m_bGbbOptionFnHasError = true;
+ m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSET_OPT_PRINT_BAD_ARGS);
+ return MIstatus::failure;
+ }
+
+ const CMIUtilString strOption(vrWords[0]);
+ CMIUtilString strOptionKey;
+ if (CMIUtilString::Compare(strOption, "char-array-as-string"))
+ strOptionKey = m_rLLDBDebugSessionInfo.m_constStrPrintCharArrayAsString;
+ else if (CMIUtilString::Compare(strOption, "expand-aggregates"))
+ strOptionKey = m_rLLDBDebugSessionInfo.m_constStrPrintExpandAggregates;
+ else if (CMIUtilString::Compare(strOption, "aggregate-field-names"))
+ strOptionKey = m_rLLDBDebugSessionInfo.m_constStrPrintAggregateFieldNames;
+ else
+ {
+ m_bGbbOptionFnHasError = true;
+ m_strGdbOptionFnError = CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_GDBSET_OPT_PRINT_UNKNOWN_OPTION), strOption.c_str());
+ return MIstatus::failure;
+ }
+
+ const bool bOptionValue(bArgOn);
+ if (!m_rLLDBDebugSessionInfo.SharedDataAdd<bool>(strOptionKey, bOptionValue))
+ {
+ m_bGbbOptionFnHasError = false;
+ SetError(CMIUtilString::Format(MIRSRC(IDS_DBGSESSION_ERR_SHARED_DATA_ADD), m_cmdData.strMiCmd.c_str(), strOptionKey.c_str()));
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
// Details: Carry out work to complete the GDB set option 'solib-search-path' to prepare
// and send back information asked for.
// Type: Method.
@@ -248,8 +338,60 @@ CMICmdCmdGdbSet::OptionFnSolibSearchPath(const CMIUtilString::VecString_t &vrWor
}
//++ ------------------------------------------------------------------------------------
-// Details: Carry out work to complete the GDB set option to prepare and send back information
-// asked for.
+// Details: Carry out work to complete the GDB set option 'output-radix' 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::OptionFnOutputRadix(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 &rStrValOutputRadix(vrWords[0]);
+
+ CMICmnLLDBDebugSessionInfoVarObj::varFormat_e format = CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Invalid;
+ MIint64 radix;
+ if (rStrValOutputRadix.ExtractNumber(radix))
+ {
+ switch (radix)
+ {
+ case 8:
+ format = CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Octal;
+ break;
+ case 10:
+ format = CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Natural;
+ break;
+ case 16:
+ format = CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Hex;
+ break;
+ default:
+ format = CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Invalid;
+ break;
+ }
+ }
+ if (format == CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Invalid)
+ {
+ m_bGbbOptionFnHasError = false;
+ SetError(CMIUtilString::Format(MIRSRC(IDS_DBGSESSION_ERR_SHARED_DATA_ADD), m_cmdData.strMiCmd.c_str(), "Output Radix"));
+ return MIstatus::failure;
+ }
+ CMICmnLLDBDebugSessionInfoVarObj::VarObjSetFormat(format);
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Carry out work to complete the GDB set option to prepare and send back the
+// requested information.
// Type: Method.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
@@ -261,8 +403,8 @@ 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
+ // Do nothing - intentional. This is a fallback function to do nothing.
+ // This allows the search for gdb-set options to always succeed when the option is not
// found (implemented).
return MIstatus::success;
diff --git a/tools/lldb-mi/MICmdCmdGdbSet.h b/tools/lldb-mi/MICmdCmdGdbSet.h
index 59ddc57e1a2d..0095f81838d1 100644
--- a/tools/lldb-mi/MICmdCmdGdbSet.h
+++ b/tools/lldb-mi/MICmdCmdGdbSet.h
@@ -1,4 +1,4 @@
-//===-- MICmdCmdGdbSet.h ------------- ---------------------*- C++ -*-===//
+//===-- MICmdCmdGdbSet.h ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,12 +7,9 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdGdbSet.h
-//
// Overview: CMICmdCmdGdbSet interface.
//
-// To implement new MI commands derive a new command class from the command base
+// 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
@@ -20,13 +17,6 @@
// 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
@@ -79,7 +69,10 @@ class CMICmdCmdGdbSet : public CMICmdBase
// Methods:
private:
bool GetOptionFn(const CMIUtilString &vrGdbOptionName, FnGdbOptionPtr &vrwpFn) const;
+ bool OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords);
+ bool OptionFnPrint(const CMIUtilString::VecString_t &vrWords);
bool OptionFnSolibSearchPath(const CMIUtilString::VecString_t &vrWords);
+ bool OptionFnOutputRadix(const CMIUtilString::VecString_t &vrWords);
bool OptionFnFallback(const CMIUtilString::VecString_t &vrWords);
// Attributes:
diff --git a/tools/lldb-mi/MICmdCmdGdbShow.cpp b/tools/lldb-mi/MICmdCmdGdbShow.cpp
new file mode 100644
index 000000000000..f1f40ccbed1a
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdGdbShow.cpp
@@ -0,0 +1,340 @@
+//===-- MICmdCmdGdbShow.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Overview: CMICmdCmdGdbShow implementation.
+
+// Third party headers:
+#include "lldb/API/SBCompileUnit.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBLanguageRuntime.h"
+#include "lldb/API/SBThread.h"
+
+// In-house headers:
+#include "MICmdCmdGdbShow.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmdArgValString.h"
+#include "MICmdArgValListOfN.h"
+#include "MICmdArgValOptionLong.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+
+// Instantiations:
+const CMICmdCmdGdbShow::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbShow::ms_mapGdbOptionNameToFnGdbOptionPtr = {
+ {"target-async", &CMICmdCmdGdbShow::OptionFnTargetAsync},
+ {"print", &CMICmdCmdGdbShow::OptionFnPrint},
+ {"language", &CMICmdCmdGdbShow::OptionFnLanguage},
+ {"fallback", &CMICmdCmdGdbShow::OptionFnFallback}};
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdGdbShow constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdGdbShow::CMICmdCmdGdbShow(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-show";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdGdbShow::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdGdbShow destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdGdbShow::~CMICmdCmdGdbShow(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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdGdbShow::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 is executed in this function.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdGdbShow::Execute(void)
+{
+ CMICMDBASE_GETOPTION(pArgGdbOption, ListOfN, m_constStrArgNamedGdbOption);
+ const CMICmdArgValListBase::VecArgObjPtr_t &rVecWords(pArgGdbOption->GetExpectedOptions());
+
+ // Get the gdb-show option to carry out. This option will be used as an action
+ // which should be done. Further arguments will be used as parameters for it.
+ 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 to 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() method.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdGdbShow::Acknowledge(void)
+{
+ // Print error if option isn't recognized:
+ // ^error,msg="The request '%s' was not recognized, not implemented"
+ 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;
+ }
+
+ // ^done,value="%s"
+ if (m_bGdbOptionFnSuccessful && !m_strValue.empty())
+ {
+ 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;
+ }
+ else if (m_bGdbOptionFnSuccessful)
+ {
+ // Ignore empty value (for fallback)
+ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ // Print error if request failed:
+ // ^error,msg="The request '%s' failed.
+ 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 *
+CMICmdCmdGdbShow::CreateSelf(void)
+{
+ return new CMICmdCmdGdbShow();
+}
+
+//++ ------------------------------------------------------------------------------------
+// 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
+CMICmdCmdGdbShow::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 show option 'target-async' to prepare
+// and send back the requested information.
+// Type: Method.
+// Args: vrWords - (R) List of additional parameters used by this option.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdGdbShow::OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords)
+{
+ MIunused(vrWords);
+
+ // Get async mode
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ const bool bAsyncMode = rSessionInfo.GetDebugger().GetAsync();
+
+ m_strValue = bAsyncMode ? "on" : "off";
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Carry out work to complete the GDB show option 'print' to prepare and send
+// back the requested information.
+// Type: Method.
+// Args: vrWords - (R) List of additional parameters used by this option.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdGdbShow::OptionFnPrint(const CMIUtilString::VecString_t &vrWords)
+{
+ const bool bAllArgs(vrWords.size() == 1);
+ if (!bAllArgs)
+ {
+ m_bGbbOptionFnHasError = true;
+ m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSHOW_OPT_PRINT_BAD_ARGS);
+ return MIstatus::failure;
+ }
+
+ const CMIUtilString strOption(vrWords[0]);
+ CMIUtilString strOptionKey;
+ bool bOptionValueDefault = false;
+ if (CMIUtilString::Compare(strOption, "char-array-as-string"))
+ strOptionKey = m_rLLDBDebugSessionInfo.m_constStrPrintCharArrayAsString;
+ else if (CMIUtilString::Compare(strOption, "expand-aggregates"))
+ strOptionKey = m_rLLDBDebugSessionInfo.m_constStrPrintExpandAggregates;
+ else if (CMIUtilString::Compare(strOption, "aggregate-field-names"))
+ {
+ strOptionKey = m_rLLDBDebugSessionInfo.m_constStrPrintAggregateFieldNames;
+ bOptionValueDefault = true;
+ }
+ else
+ {
+ m_bGbbOptionFnHasError = true;
+ m_strGdbOptionFnError = CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_GDBSHOW_OPT_PRINT_UNKNOWN_OPTION), strOption.c_str());
+ return MIstatus::failure;
+ }
+
+ bool bOptionValue = false;
+ bOptionValue = bOptionValueDefault ? !m_rLLDBDebugSessionInfo.SharedDataRetrieve<bool>(strOptionKey, bOptionValue) || bOptionValue
+ : m_rLLDBDebugSessionInfo.SharedDataRetrieve<bool>(strOptionKey, bOptionValue) && bOptionValue;
+
+ m_strValue = bOptionValue ? "on" : "off";
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Carry out work to complete the GDB show option 'language' to prepare
+// and send back the requested information.
+// Type: Method.
+// Args: vrWords - (R) List of additional parameters used by this option.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdGdbShow::OptionFnLanguage(const CMIUtilString::VecString_t &vrWords)
+{
+ MIunused(vrWords);
+
+ // Get current language
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ lldb::SBThread sbThread = rSessionInfo.GetProcess().GetSelectedThread();
+ const lldb::SBFrame sbFrame = sbThread.GetSelectedFrame();
+ lldb::SBCompileUnit sbCompileUnit = sbFrame.GetCompileUnit();
+ const lldb::LanguageType eLanguageType = sbCompileUnit.GetLanguage();
+
+ m_strValue = lldb::SBLanguageRuntime::GetNameForLanguageType(eLanguageType);
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Carry out work to complete the GDB show option to prepare and send back the
+// requested information.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdGdbShow::OptionFnFallback(const CMIUtilString::VecString_t &vrWords)
+{
+ MIunused(vrWords);
+
+ // Do nothing - intentional. This is a fallback function to do nothing.
+ // This allows the search for gdb-show options to always succeed when the option is not
+ // found (implemented).
+
+ return MIstatus::success;
+}
diff --git a/tools/lldb-mi/MICmdCmdGdbShow.h b/tools/lldb-mi/MICmdCmdGdbShow.h
new file mode 100644
index 000000000000..5cb4cb58f809
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdGdbShow.h
@@ -0,0 +1,86 @@
+//===-- MICmdCmdGdbShow.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Overview: CMICmdCmdGdbShow 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.
+
+#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-show".
+// 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.
+//--
+class CMICmdCmdGdbShow : public CMICmdBase
+{
+ // Statics:
+ public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase *CreateSelf(void);
+
+ // Methods:
+ public:
+ /* ctor */ CMICmdCmdGdbShow(void);
+
+ // Overridden:
+ public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute(void);
+ virtual bool Acknowledge(void);
+ virtual bool ParseArgs(void);
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdGdbShow(void);
+
+ // Typedefs:
+ private:
+ typedef bool (CMICmdCmdGdbShow::*FnGdbOptionPtr)(const CMIUtilString::VecString_t &vrWords);
+ typedef std::map<CMIUtilString, FnGdbOptionPtr> MapGdbOptionNameToFnGdbOptionPtr_t;
+
+ // Methods:
+ private:
+ bool GetOptionFn(const CMIUtilString &vrGdbOptionName, FnGdbOptionPtr &vrwpFn) const;
+ bool OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords);
+ bool OptionFnPrint(const CMIUtilString::VecString_t &vrWords);
+ bool OptionFnLanguage(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;
+ CMIUtilString m_strValue;
+};
diff --git a/tools/lldb-mi/MICmdCmdGdbThread.cpp b/tools/lldb-mi/MICmdCmdGdbThread.cpp
index e840338a2e41..40f2eeccb6b4 100644
--- a/tools/lldb-mi/MICmdCmdGdbThread.cpp
+++ b/tools/lldb-mi/MICmdCmdGdbThread.cpp
@@ -7,17 +7,7 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdCmdGdbThread.h b/tools/lldb-mi/MICmdCmdGdbThread.h
index 5fac70b8b39a..a4b8596a47c1 100644
--- a/tools/lldb-mi/MICmdCmdGdbThread.h
+++ b/tools/lldb-mi/MICmdCmdGdbThread.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdGdbThread.h
-//
// Overview: CMICmdCmdGdbThread interface.
//
// To implement new MI commands derive a new command class from the command base
@@ -20,13 +17,6 @@
// 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
diff --git a/tools/lldb-mi/MICmdCmdMiscellanous.cpp b/tools/lldb-mi/MICmdCmdMiscellanous.cpp
index 4e4e1b986e8a..37cae404ad7d 100644
--- a/tools/lldb-mi/MICmdCmdMiscellanous.cpp
+++ b/tools/lldb-mi/MICmdCmdMiscellanous.cpp
@@ -7,20 +7,10 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -84,7 +74,7 @@ bool
CMICmdCmdGdbExit::Execute(void)
{
CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag(true);
- const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.GetProcess().Detach();
+ const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.GetProcess().Destroy();
// Do not check for sbErr.Fail() here, m_lldbProcess is likely !IsValid()
return MIstatus::success;
@@ -249,7 +239,7 @@ CMICmdCmdListThreadGroups::Execute(void)
if (thread.IsValid())
{
CMICmnMIValueTuple miTuple;
- if (!rSessionInfo.MIResponseFormThreadInfo2(m_cmdData, thread, miTuple))
+ if (!rSessionInfo.MIResponseFormThreadInfo(m_cmdData, thread, CMICmnLLDBDebugSessionInfo::eThreadInfoFormat_NoFrames, miTuple))
return MIstatus::failure;
m_vecMIValueTuple.push_back(miTuple);
@@ -340,8 +330,8 @@ CMICmdCmdListThreadGroups::Acknowledge(void)
if (rSessionInfo.GetTarget().IsValid())
{
lldb::SBTarget sbTrgt = rSessionInfo.GetTarget();
- const MIchar *pDir = sbTrgt.GetExecutable().GetDirectory();
- const MIchar *pFileName = sbTrgt.GetExecutable().GetFilename();
+ const char *pDir = sbTrgt.GetExecutable().GetDirectory();
+ const char *pFileName = sbTrgt.GetExecutable().GetFilename();
const CMIUtilString strFile(CMIUtilString::Format("%s/%s", pDir, pFileName));
const CMICmnMIValueConst miValueConst4(strFile);
const CMICmnMIValueResult miValueResult4("executable", miValueConst4);
@@ -409,7 +399,7 @@ CMICmdCmdListThreadGroups::CreateSelf(void)
// Throws: None.
//--
CMICmdCmdInterpreterExec::CMICmdCmdInterpreterExec(void)
- : m_constStrArgNamedInterpreter("intepreter")
+ : m_constStrArgNamedInterpreter("interpreter")
, m_constStrArgNamedCommand("command")
{
// Command factory matches this name with that received from the stdin stream
@@ -493,19 +483,12 @@ CMICmdCmdInterpreterExec::Acknowledge(void)
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);
diff --git a/tools/lldb-mi/MICmdCmdMiscellanous.h b/tools/lldb-mi/MICmdCmdMiscellanous.h
index fd990940e44d..ffc691cdc927 100644
--- a/tools/lldb-mi/MICmdCmdMiscellanous.h
+++ b/tools/lldb-mi/MICmdCmdMiscellanous.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdMiscellanous.h
-//
// Overview: CMICmdCmdGdbExit interface.
// CMICmdCmdListThreadGroups interface.
// CMICmdCmdInterpreterExec interface.
@@ -23,13 +20,6 @@
// 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
diff --git a/tools/lldb-mi/MICmdCmdStack.cpp b/tools/lldb-mi/MICmdCmdStack.cpp
index 4ab7164a30b7..7f767e727f97 100644
--- a/tools/lldb-mi/MICmdCmdStack.cpp
+++ b/tools/lldb-mi/MICmdCmdStack.cpp
@@ -7,20 +7,12 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdStack.cpp
-//
// Overview: CMICmdCmdStackInfoDepth implementation.
+// CMICmdCmdStackInfoFrame 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.
-//--
+// CMICmdCmdStackSelectFrame implementation.
// Third Party Headers:
#include "lldb/API/SBThread.h"
@@ -37,6 +29,7 @@
#include "MICmdArgValThreadGrp.h"
#include "MICmdArgValOptionLong.h"
#include "MICmdArgValOptionShort.h"
+#include "MICmdArgValPrintValues.h"
#include "MICmdArgValListOfN.h"
//++ ------------------------------------------------------------------------------------
@@ -158,6 +151,113 @@ CMICmdCmdStackInfoDepth::CreateSelf(void)
//---------------------------------------------------------------------------------------
//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackInfoFrame constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackInfoFrame::CMICmdCmdStackInfoFrame(void)
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "stack-info-frame";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdStackInfoFrame::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackInfoFrame destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackInfoFrame::~CMICmdCmdStackInfoFrame(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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdStackInfoFrame::ParseArgs(void)
+{
+ return 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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdStackInfoFrame::Execute(void)
+{
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
+ if (!sbProcess.IsValid())
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str()));
+ return MIstatus::failure;
+ }
+
+ lldb::SBThread sbThread = sbProcess.GetSelectedThread();
+ MIuint nFrameId = sbThread.GetSelectedFrame().GetFrameID();
+ if (!rSessionInfo.MIResponseFormFrameInfo(sbThread, nFrameId, CMICmnLLDBDebugSessionInfo::eFrameInfoFormat_NoArguments, m_miValueTuple))
+ 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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdStackInfoFrame::Acknowledge(void)
+{
+ const CMICmnMIValueResult miValueResult("frame", m_miValueTuple);
+ 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 *
+CMICmdCmdStackInfoFrame::CreateSelf(void)
+{
+ return new CMICmdCmdStackInfoFrame();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdStackListFrames constructor.
// Type: Method.
// Args: None.
@@ -257,7 +357,7 @@ CMICmdCmdStackListFrames::Execute(void)
for (MIuint nLevel = nFrameLow; nLevel < nThreadFrames; nLevel++)
{
CMICmnMIValueTuple miValueTuple;
- if (!rSessionInfo.MIResponseFormFrameInfo(thread, nLevel, miValueTuple))
+ if (!rSessionInfo.MIResponseFormFrameInfo(thread, nLevel, CMICmnLLDBDebugSessionInfo::eFrameInfoFormat_NoArguments, miValueTuple))
return MIstatus::failure;
const CMICmnMIValueResult miValueResult8("frame", miValueTuple);
@@ -350,9 +450,8 @@ CMICmdCmdStackListArguments::CMICmdCmdStackListArguments(void)
, m_miValueList(true)
, m_constStrArgThread("thread")
, m_constStrArgPrintValues("print-values")
- , m_constStrArgNoValues("no-values")
- , m_constStrArgAllValues("all-values")
- , m_constStrArgSimpleValues("simple-values")
+ , m_constStrArgFrameLow("low-frame")
+ , m_constStrArgFrameHigh("high-frame")
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "stack-list-arguments";
@@ -386,10 +485,9 @@ 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, false, true)));
- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgNoValues, false, true)));
- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgAllValues, false, true)));
- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgSimpleValues, false, true)));
+ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValPrintValues(m_constStrArgPrintValues, true, true)));
+ 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());
}
@@ -406,10 +504,9 @@ bool
CMICmdCmdStackListArguments::Execute(void)
{
CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread);
- CMICMDBASE_GETOPTION(pArgPrintValues, Number, m_constStrArgPrintValues);
- CMICMDBASE_GETOPTION(pArgNoValues, OptionLong, m_constStrArgNoValues);
- CMICMDBASE_GETOPTION(pArgAllValues, OptionLong, m_constStrArgAllValues);
- CMICMDBASE_GETOPTION(pArgSimpleValues, OptionLong, m_constStrArgSimpleValues);
+ CMICMDBASE_GETOPTION(pArgPrintValues, PrintValues, m_constStrArgPrintValues);
+ 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;
@@ -422,26 +519,19 @@ CMICmdCmdStackListArguments::Execute(void)
}
}
- CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat;
- if (pArgPrintValues->GetFound())
+ const CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat = static_cast<CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e>(pArgPrintValues->GetValue());
+
+ MIuint nFrameLow = 0;
+ MIuint nFrameHigh = UINT32_MAX;
+ if (pArgFrameLow->GetFound() && pArgFrameHigh->GetFound())
{
- const MIuint nPrintValues = pArgPrintValues->GetValue();
- if (nPrintValues >= CMICmnLLDBDebugSessionInfo::kNumVariableInfoFormats)
- {
- SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str()));
- return MIstatus::failure;
- }
- eVarInfoFormat = static_cast<CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e>(nPrintValues);
+ nFrameLow = pArgFrameLow->GetValue();
+ nFrameHigh = pArgFrameHigh->GetValue() + 1;
}
- else if (pArgNoValues->GetFound())
- eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_NoValues;
- else if (pArgAllValues->GetFound())
- eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues;
- else if (pArgSimpleValues->GetFound())
- eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_SimpleValues;
- else
+ else if (pArgFrameLow->GetFound() || pArgFrameHigh->GetFound())
{
- SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str()));
+ // Only low-frame or high-frame was specified but both are required
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_FRAME_RANGE_INVALID), m_cmdData.strMiCmd.c_str()));
return MIstatus::failure;
}
@@ -460,12 +550,20 @@ CMICmdCmdStackListArguments::Execute(void)
}
const MIuint nFrames = thread.GetNumFrames();
- for (MIuint i = 0; i < nFrames; i++)
+ if (nFrameLow >= nFrames)
+ {
+ // The low-frame is larger than the actual number of frames
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_FRAME_RANGE_INVALID), m_cmdData.strMiCmd.c_str()));
+ return MIstatus::failure;
+ }
+
+ nFrameHigh = std::min(nFrameHigh, nFrames);
+ for (MIuint i = nFrameLow; i < nFrameHigh; i++)
{
lldb::SBFrame frame = thread.GetFrameAtIndex(i);
CMICmnMIValueList miValueList(true);
const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments;
- if (!rSessionInfo.MIResponseFormVariableInfo3(frame, maskVarTypes, eVarInfoFormat, miValueList))
+ if (!rSessionInfo.MIResponseFormVariableInfo(frame, maskVarTypes, eVarInfoFormat, miValueList))
return MIstatus::failure;
const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%d", i));
const CMICmnMIValueResult miValueResult("level", miValueConst);
@@ -540,9 +638,6 @@ CMICmdCmdStackListLocals::CMICmdCmdStackListLocals(void)
, m_constStrArgThread("thread")
, m_constStrArgFrame("frame")
, m_constStrArgPrintValues("print-values")
- , m_constStrArgNoValues("no-values")
- , m_constStrArgAllValues("all-values")
- , m_constStrArgSimpleValues("simple-values")
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "stack-list-locals";
@@ -578,10 +673,7 @@ CMICmdCmdStackListLocals::ParseArgs(void)
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, false, true)));
- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgNoValues, false, true)));
- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgAllValues, false, true)));
- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgSimpleValues, false, true)));
+ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValPrintValues(m_constStrArgPrintValues, true, true)));
return (bOk && ParseValidateCmdOptions());
}
@@ -599,10 +691,7 @@ CMICmdCmdStackListLocals::Execute(void)
{
CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread);
CMICMDBASE_GETOPTION(pArgFrame, OptionLong, m_constStrArgFrame);
- CMICMDBASE_GETOPTION(pArgPrintValues, Number, m_constStrArgPrintValues);
- CMICMDBASE_GETOPTION(pArgNoValues, OptionLong, m_constStrArgNoValues);
- CMICMDBASE_GETOPTION(pArgAllValues, OptionLong, m_constStrArgAllValues);
- CMICMDBASE_GETOPTION(pArgSimpleValues, OptionLong, m_constStrArgSimpleValues);
+ CMICMDBASE_GETOPTION(pArgPrintValues, PrintValues, m_constStrArgPrintValues);
// Retrieve the --thread option's thread ID (only 1)
MIuint64 nThreadId = UINT64_MAX;
@@ -625,28 +714,7 @@ CMICmdCmdStackListLocals::Execute(void)
}
}
- CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat;
- if (pArgPrintValues->GetFound())
- {
- const MIuint nPrintValues = pArgPrintValues->GetValue();
- if (nPrintValues >= CMICmnLLDBDebugSessionInfo::kNumVariableInfoFormats)
- {
- SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str()));
- return MIstatus::failure;
- }
- eVarInfoFormat = static_cast<CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e>(nPrintValues);
- }
- else if (pArgNoValues->GetFound())
- eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_NoValues;
- else if (pArgAllValues->GetFound())
- eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues;
- else if (pArgSimpleValues->GetFound())
- eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_SimpleValues;
- else
- {
- SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str()));
- return MIstatus::failure;
- }
+ const CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat = static_cast<CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e>(pArgPrintValues->GetValue());
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
@@ -717,3 +785,288 @@ CMICmdCmdStackListLocals::CreateSelf(void)
{
return new CMICmdCmdStackListLocals();
}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackListVariables constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackListVariables::CMICmdCmdStackListVariables(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-variables";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdStackListVariables::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackListVariables destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackListVariables::~CMICmdCmdStackListVariables(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
+CMICmdCmdStackListVariables::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 CMICmdArgValPrintValues(m_constStrArgPrintValues, 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
+CMICmdCmdStackListVariables::Execute(void)
+{
+ CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread);
+ CMICMDBASE_GETOPTION(pArgFrame, OptionLong, m_constStrArgFrame);
+ CMICMDBASE_GETOPTION(pArgPrintValues, PrintValues, 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;
+ }
+ }
+
+ 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;
+ }
+ }
+
+ const CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat = static_cast<CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e>(pArgPrintValues->GetValue());
+
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
+ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.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;
+ }
+
+ lldb::SBFrame frame = (nFrame != UINT64_MAX) ? thread.GetFrameAtIndex(nFrame) : thread.GetSelectedFrame();
+
+ CMICmnMIValueList miValueList(true);
+ const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments | CMICmnLLDBDebugSessionInfo::eVariableType_Locals;
+ if (!rSessionInfo.MIResponseFormVariableInfo(frame, maskVarTypes, eVarInfoFormat, miValueList, 10, true))
+ 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
+CMICmdCmdStackListVariables::Acknowledge(void)
+{
+ if (m_bThreadInvalid)
+ {
+ // MI print "%s^done,variables=[]"
+ const CMICmnMIValueList miValueList(true);
+ const CMICmnMIValueResult miValueResult("variables", miValueList);
+ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ // MI print "%s^done,variables=[%s]"
+ const CMICmnMIValueResult miValueResult("variables", 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 *
+CMICmdCmdStackListVariables::CreateSelf(void)
+{
+ return new CMICmdCmdStackListVariables();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackSelectFrame constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackSelectFrame::CMICmdCmdStackSelectFrame(void)
+ : m_bFrameInvalid(false)
+ , m_constStrArgFrame("frame")
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "stack-select-frame";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdStackSelectFrame::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackSelectFrame destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackSelectFrame::~CMICmdCmdStackSelectFrame(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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdStackSelectFrame::ParseArgs(void)
+{
+ bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrame, 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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdStackSelectFrame::Execute(void)
+{
+ CMICMDBASE_GETOPTION(pArgFrame, Number, m_constStrArgFrame);
+
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ lldb::SBThread sbThread = rSessionInfo.GetProcess().GetSelectedThread();
+
+ const MIuint nFrameId = pArgFrame->GetValue();
+ m_bFrameInvalid = (nFrameId >= sbThread.GetNumFrames());
+ if (m_bFrameInvalid)
+ return MIstatus::success;
+
+ lldb::SBFrame sbFrame = sbThread.SetSelectedFrame(nFrameId);
+ m_bFrameInvalid = !sbFrame.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 - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdStackSelectFrame::Acknowledge(void)
+{
+ if (m_bFrameInvalid)
+ {
+ // MI print "%s^error,msg=\"Command '-stack-select-frame'. Frame ID invalid\""
+ const CMICmnMIValueConst miValueConst(
+ CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FRAME_INVALID), m_cmdData.strMiCmd.c_str()));
+ const CMICmnMIValueResult miValueResult("msg", miValueConst);
+ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+ }
+
+ 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 *
+CMICmdCmdStackSelectFrame::CreateSelf(void)
+{
+ return new CMICmdCmdStackSelectFrame();
+}
diff --git a/tools/lldb-mi/MICmdCmdStack.h b/tools/lldb-mi/MICmdCmdStack.h
index ebef7e197f5f..ed141fcf942f 100644
--- a/tools/lldb-mi/MICmdCmdStack.h
+++ b/tools/lldb-mi/MICmdCmdStack.h
@@ -7,13 +7,12 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdStack.h
-//
// Overview: CMICmdCmdStackInfoDepth interface.
+// CMICmdCmdStackInfoFrame interface.
// CMICmdCmdStackListFrames interface.
// CMICmdCmdStackListArguments interface.
// CMICmdCmdStackListLocals interface.
+// CMICmdCmdStackSelectFrame 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
@@ -23,19 +22,13 @@
// 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"
+#include "MICmnMIValueTuple.h"
//++ ============================================================================
// Details: MI command class. MI commands derived from the command base class.
@@ -73,6 +66,35 @@ class CMICmdCmdStackInfoDepth : public CMICmdBase
//++ ============================================================================
// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "stack-info-frame".
+//--
+class CMICmdCmdStackInfoFrame : public CMICmdBase
+{
+ // Statics:
+ public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase *CreateSelf(void);
+
+ // Methods:
+ public:
+ /* ctor */ CMICmdCmdStackInfoFrame(void);
+
+ // Overridden:
+ public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute(void);
+ virtual bool Acknowledge(void);
+ virtual bool ParseArgs(void);
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdStackInfoFrame(void);
+
+ // Attributes:
+ private:
+ CMICmnMIValueTuple m_miValueTuple;
+};
+
+//++ ============================================================================
+// 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.
@@ -144,9 +166,8 @@ class CMICmdCmdStackListArguments : public CMICmdBase
CMICmnMIValueList m_miValueList;
const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
const CMIUtilString m_constStrArgPrintValues;
- const CMIUtilString m_constStrArgNoValues;
- const CMIUtilString m_constStrArgAllValues;
- const CMIUtilString m_constStrArgSimpleValues;
+ const CMIUtilString m_constStrArgFrameLow;
+ const CMIUtilString m_constStrArgFrameHigh;
};
//++ ============================================================================
@@ -183,7 +204,67 @@ class CMICmdCmdStackListLocals : public CMICmdBase
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;
- const CMIUtilString m_constStrArgNoValues;
- const CMIUtilString m_constStrArgAllValues;
- const CMIUtilString m_constStrArgSimpleValues;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "stack-list-variables".
+//--
+class CMICmdCmdStackListVariables : public CMICmdBase
+{
+ // Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase *CreateSelf(void);
+
+ // Methods:
+public:
+ /* ctor */ CMICmdCmdStackListVariables(void);
+
+ // Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute(void);
+ virtual bool Acknowledge(void);
+ virtual bool ParseArgs(void);
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdStackListVariables(void);
+
+ // Attributes
+private:
+ bool m_bThreadInvalid; // True = yes invalid thread, false = thread object valid
+ CMICmnMIValueList m_miValueList;
+ const CMIUtilString m_constStrArgThread;
+ const CMIUtilString m_constStrArgFrame;
+ const CMIUtilString m_constStrArgPrintValues;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "stack-select-frame".
+//--
+class CMICmdCmdStackSelectFrame : public CMICmdBase
+{
+ // Statics:
+ public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase *CreateSelf(void);
+
+ // Methods:
+ public:
+ /* ctor */ CMICmdCmdStackSelectFrame(void);
+
+ // Overridden:
+ public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute(void);
+ virtual bool Acknowledge(void);
+ virtual bool ParseArgs(void);
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdStackSelectFrame(void);
+
+ // Attributes:
+ private:
+ bool m_bFrameInvalid; // True = yes invalid frame, false = ok
+ const CMIUtilString m_constStrArgFrame;
};
diff --git a/tools/lldb-mi/MICmdCmdSupportInfo.cpp b/tools/lldb-mi/MICmdCmdSupportInfo.cpp
index c2fc572f8c17..2d04ef8dddf9 100644
--- a/tools/lldb-mi/MICmdCmdSupportInfo.cpp
+++ b/tools/lldb-mi/MICmdCmdSupportInfo.cpp
@@ -7,17 +7,7 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdCmdSupportInfo.h b/tools/lldb-mi/MICmdCmdSupportInfo.h
index b643d4af1aa4..a8c22526484d 100644
--- a/tools/lldb-mi/MICmdCmdSupportInfo.h
+++ b/tools/lldb-mi/MICmdCmdSupportInfo.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdSupportInfo.h
-//
// Overview: CMICmdCmdSupportInfoMiCmdQuery interface.
//
// To implement new MI commands derive a new command class from the command base
@@ -20,13 +17,6 @@
// 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
diff --git a/tools/lldb-mi/MICmdCmdSupportList.cpp b/tools/lldb-mi/MICmdCmdSupportList.cpp
index 02728b95feb0..6cf4b0b533bc 100644
--- a/tools/lldb-mi/MICmdCmdSupportList.cpp
+++ b/tools/lldb-mi/MICmdCmdSupportList.cpp
@@ -7,17 +7,7 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdCmdSupportList.h b/tools/lldb-mi/MICmdCmdSupportList.h
index 24267579d676..16c140bca349 100644
--- a/tools/lldb-mi/MICmdCmdSupportList.h
+++ b/tools/lldb-mi/MICmdCmdSupportList.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdSupportList.h
-//
// Overview: CMICmdCmdSupportListFeatures interface.
//
// To implement new MI commands derive a new command class from the command base
@@ -20,13 +17,6 @@
// 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
diff --git a/tools/lldb-mi/MICmdCmdSymbol.cpp b/tools/lldb-mi/MICmdCmdSymbol.cpp
new file mode 100644
index 000000000000..2649389d7686
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdSymbol.cpp
@@ -0,0 +1,173 @@
+//===-- MICmdCmdSymbol.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Overview: CMICmdCmdSymbolListLines implementation.
+
+// Third Party Headers:
+#include "lldb/API/SBCommandInterpreter.h"
+
+// In-house headers:
+#include "MICmdArgValFile.h"
+#include "MICmdCmdSymbol.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueList.h"
+#include "MICmnMIValueTuple.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdSymbolListLines constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdSymbolListLines::CMICmdCmdSymbolListLines(void)
+ : m_constStrArgNameFile("file")
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "symbol-list-lines";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdSymbolListLines::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdSymbolListLines destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdSymbolListLines::~CMICmdCmdSymbolListLines(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
+CMICmdCmdSymbolListLines::ParseArgs(void)
+{
+ bool 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: -symbol-list-lines file
+// Ref: http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Symbol-Query.html#GDB_002fMI-Symbol-Query
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool
+CMICmdCmdSymbolListLines::Execute(void)
+{
+ CMICMDBASE_GETOPTION(pArgFile, File, m_constStrArgNameFile);
+
+ const CMIUtilString &strFilePath(pArgFile->GetValue());
+ const CMIUtilString strCmd(CMIUtilString::Format("target modules dump line-table \"%s\"", strFilePath.AddSlashes().c_str()));
+
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult);
+ 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
+CMICmdCmdSymbolListLines::Acknowledge(void)
+{
+ if (m_lldbResult.GetErrorSize() > 0)
+ {
+ const char *pLldbErr = m_lldbResult.GetError();
+ const CMIUtilString strMsg(CMIUtilString(pLldbErr).StripCRAll());
+ const CMICmnMIValueConst miValueConst(strMsg);
+ const CMICmnMIValueResult miValueResult("message", miValueConst);
+ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
+ m_miResultRecord = miRecordResult;
+ }
+ else
+ {
+ CMIUtilString::VecString_t vecLines;
+ const CMIUtilString strLldbMsg(m_lldbResult.GetOutput());
+ const MIuint nLines(strLldbMsg.SplitLines(vecLines));
+
+ CMICmnMIValueList miValueList(true);
+ for (MIuint i = 1; i < nLines; ++i)
+ {
+ // String looks like:
+ // 0x0000000100000e70: /path/to/file:3[:4]
+ const CMIUtilString &rLine(vecLines[i]);
+
+ // 0x0000000100000e70: /path/to/file:3[:4]
+ // ^^^^^^^^^^^^^^^^^^ -- pc
+ const size_t nAddrEndPos = rLine.find(':');
+ const CMIUtilString strAddr(rLine.substr(0, nAddrEndPos).c_str());
+ const CMICmnMIValueConst miValueConst(strAddr);
+ const CMICmnMIValueResult miValueResult("pc", miValueConst);
+ CMICmnMIValueTuple miValueTuple(miValueResult);
+
+ // 0x0000000100000e70: /path/to/file:3[:4]
+ // ^ -- line
+ const size_t nLineOrColumnStartPos = rLine.rfind(':');
+ const CMIUtilString strLineOrColumn(rLine.substr(nLineOrColumnStartPos + 1).c_str());
+ const size_t nPathOrLineStartPos = rLine.rfind(':', nLineOrColumnStartPos - 1);
+ const size_t nPathOrLineLen = nLineOrColumnStartPos - nPathOrLineStartPos - 1;
+ const CMIUtilString strPathOrLine(rLine.substr(nPathOrLineStartPos + 1, nPathOrLineLen).c_str());
+ const CMIUtilString strLine(strPathOrLine.IsNumber() ? strPathOrLine : strLineOrColumn);
+ const CMICmnMIValueConst miValueConst2(strLine);
+ const CMICmnMIValueResult miValueResult2("line", miValueConst2);
+ bool bOk = miValueTuple.Add(miValueResult2);
+
+ bOk = bOk && miValueList.Add(miValueTuple);
+ if (!bOk)
+ return MIstatus::failure;
+ }
+
+ // MI print "%s^done,lines=[{pc=\"%d\",line=\"%d\"}...]"
+ const CMICmnMIValueResult miValueResult("lines", 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 *
+CMICmdCmdSymbolListLines::CreateSelf(void)
+{
+ return new CMICmdCmdSymbolListLines();
+}
diff --git a/tools/lldb-mi/MICmdCmdSymbol.h b/tools/lldb-mi/MICmdCmdSymbol.h
new file mode 100644
index 000000000000..449d8aed81b0
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdSymbol.h
@@ -0,0 +1,57 @@
+//===-- MICmdCmdSymbol.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Overview: CMICmdCmdSymbolListLines 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.
+
+#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 "symbol-list-lines".
+//--
+class CMICmdCmdSymbolListLines : public CMICmdBase
+{
+ // Statics:
+ public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase *CreateSelf(void);
+
+ // Methods:
+ public:
+ /* ctor */ CMICmdCmdSymbolListLines(void);
+
+ // Overridden:
+ public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute(void);
+ virtual bool Acknowledge(void);
+ virtual bool ParseArgs(void);
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdSymbolListLines(void);
+
+ // Attributes:
+ private:
+ lldb::SBCommandReturnObject m_lldbResult;
+ const CMIUtilString m_constStrArgNameFile;
+};
diff --git a/tools/lldb-mi/MICmdCmdTarget.cpp b/tools/lldb-mi/MICmdCmdTarget.cpp
index c3ef0b44e806..6655682eee38 100644
--- a/tools/lldb-mi/MICmdCmdTarget.cpp
+++ b/tools/lldb-mi/MICmdCmdTarget.cpp
@@ -7,17 +7,7 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -32,6 +22,9 @@
#include "MICmnLLDBDebugger.h"
#include "MICmnLLDBDebugSessionInfo.h"
#include "MICmdArgValString.h"
+#include "MICmdArgValOptionLong.h"
+#include "MICmdArgValOptionShort.h"
+#include "MICmdArgValNumber.h"
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdTargetSelect constructor.
@@ -118,7 +111,7 @@ CMICmdCmdTargetSelect::Execute(void)
const CMIUtilString strUrl = CMIUtilString::Format("connect://%s", pArgParameters->GetValue().c_str());
// Ask LLDB to collect to the target port
- const MIchar *pPlugin("gdb-remote");
+ const char *pPlugin("gdb-remote");
lldb::SBError error;
lldb::SBProcess process = rSessionInfo.GetTarget().ConnectRemote(rSessionInfo.GetListener(), strUrl.c_str(), pPlugin, error);
@@ -214,3 +207,263 @@ CMICmdCmdTargetSelect::CreateSelf(void)
{
return new CMICmdCmdTargetSelect();
}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdTargetAttach constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdTargetAttach::CMICmdCmdTargetAttach(void)
+: m_constStrArgPid("pid")
+, m_constStrArgNamedFile("n")
+, m_constStrArgWaitFor("waitfor")
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "target-attach";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdTargetAttach::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdTargetAttach destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdTargetAttach::~CMICmdCmdTargetAttach(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
+CMICmdCmdTargetAttach::ParseArgs(void)
+{
+ bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgPid, false, true)));
+ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionShort(m_constStrArgNamedFile, false, true,
+ CMICmdArgValListBase::eArgValType_String, 1)));
+ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgWaitFor, 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.
+// Synopsis: -target-attach file
+// 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
+CMICmdCmdTargetAttach::Execute(void)
+{
+ CMICMDBASE_GETOPTION(pArgPid, Number, m_constStrArgPid);
+ CMICMDBASE_GETOPTION(pArgFile, OptionShort, m_constStrArgNamedFile);
+ CMICMDBASE_GETOPTION(pArgWaitFor, OptionLong, m_constStrArgWaitFor);
+
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+
+ // If the current target is invalid, create one
+ lldb::SBTarget target = rSessionInfo.GetTarget();
+ if (!target.IsValid())
+ {
+ target = rSessionInfo.GetDebugger().CreateTarget(NULL);
+ if (!target.IsValid())
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT), m_cmdData.strMiCmd.c_str()));
+ return MIstatus::failure;
+ }
+ }
+
+ lldb::SBError error;
+ lldb::SBListener listener;
+ if (pArgPid->GetFound() && pArgPid->GetValid())
+ {
+ lldb::pid_t pid;
+ pid = pArgPid->GetValue();
+ target.AttachToProcessWithID(listener, pid, error);
+ }
+ else if (pArgFile->GetFound() && pArgFile->GetValid())
+ {
+ bool bWaitFor = (pArgWaitFor->GetFound());
+ CMIUtilString file;
+ pArgFile->GetExpectedOption<CMICmdArgValString>(file);
+ target.AttachToProcessWithName(listener, file.c_str(), bWaitFor, error);
+ }
+ else
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_ATTACH_BAD_ARGS), m_cmdData.strMiCmd.c_str()));
+ return MIstatus::failure;
+ }
+
+ lldb::SBStream errMsg;
+ if (error.Fail())
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_ATTACH_FAILED), m_cmdData.strMiCmd.c_str(), errMsg.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
+CMICmdCmdTargetAttach::Acknowledge(void)
+{
+ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
+ m_miResultRecord = miRecordResult;
+
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ lldb::pid_t pid = rSessionInfo.GetProcess().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 *
+CMICmdCmdTargetAttach::CreateSelf(void)
+{
+ return new CMICmdCmdTargetAttach();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdTargetDetach constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdTargetDetach::CMICmdCmdTargetDetach()
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "target-detach";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdTargetDetach::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdTargetDetach destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdTargetDetach::~CMICmdCmdTargetDetach(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
+CMICmdCmdTargetDetach::ParseArgs(void)
+{
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// 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-attach file
+// 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
+CMICmdCmdTargetDetach::Execute(void)
+{
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+
+ lldb::SBProcess process = rSessionInfo.GetProcess();
+
+ if (!process.IsValid())
+ {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str()));
+ return MIstatus::failure;
+ }
+
+ process.Detach();
+
+ 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
+CMICmdCmdTargetDetach::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 *
+CMICmdCmdTargetDetach::CreateSelf(void)
+{
+ return new CMICmdCmdTargetDetach();
+}
diff --git a/tools/lldb-mi/MICmdCmdTarget.h b/tools/lldb-mi/MICmdCmdTarget.h
index 0ed790f01e02..b3810305d4d9 100644
--- a/tools/lldb-mi/MICmdCmdTarget.h
+++ b/tools/lldb-mi/MICmdCmdTarget.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdTarget.h
-//
// Overview: CMICmdCmdTargetSelect interface.
//
// To implement new MI commands derive a new command class from the command base
@@ -20,13 +17,6 @@
// 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
@@ -68,3 +58,62 @@ class CMICmdCmdTargetSelect : public CMICmdBase
const CMIUtilString m_constStrArgNamedType;
const CMIUtilString m_constStrArgNamedParameters;
};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "target-attach".
+// http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
+//--
+class CMICmdCmdTargetAttach : public CMICmdBase
+{
+ // Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase *CreateSelf(void);
+
+ // Methods:
+public:
+ /* ctor */ CMICmdCmdTargetAttach(void);
+
+ // Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute(void);
+ virtual bool Acknowledge(void);
+ virtual bool ParseArgs(void);
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdTargetAttach(void);
+
+ // Attributes:
+private:
+ const CMIUtilString m_constStrArgPid;
+ const CMIUtilString m_constStrArgNamedFile;
+ const CMIUtilString m_constStrArgWaitFor;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "target-attach".
+// http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
+//--
+class CMICmdCmdTargetDetach : public CMICmdBase
+{
+ // Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase *CreateSelf(void);
+
+ // Methods:
+public:
+ /* ctor */ CMICmdCmdTargetDetach(void);
+
+ // Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute(void);
+ virtual bool Acknowledge(void);
+ virtual bool ParseArgs(void);
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdTargetDetach(void);
+};
+
diff --git a/tools/lldb-mi/MICmdCmdThread.cpp b/tools/lldb-mi/MICmdCmdThread.cpp
index 52fd96050632..df6de269bd49 100644
--- a/tools/lldb-mi/MICmdCmdThread.cpp
+++ b/tools/lldb-mi/MICmdCmdThread.cpp
@@ -7,17 +7,7 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -105,12 +95,12 @@ CMICmdCmdThreadInfo::Execute(void)
if (m_bSingleThread)
{
thread = sbProcess.GetThreadByIndexID(nThreadId);
- m_bThreadInvalid = thread.IsValid();
- if (!m_bThreadInvalid)
+ m_bThreadInvalid = !thread.IsValid();
+ if (m_bThreadInvalid)
return MIstatus::success;
CMICmnMIValueTuple miTuple;
- if (!rSessionInfo.MIResponseFormThreadInfo3(m_cmdData, thread, miTuple))
+ if (!rSessionInfo.MIResponseFormThreadInfo(m_cmdData, thread, CMICmnLLDBDebugSessionInfo::eThreadInfoFormat_AllFrames, miTuple))
return MIstatus::failure;
m_miValueTupleThread = miTuple;
@@ -127,7 +117,7 @@ CMICmdCmdThreadInfo::Execute(void)
if (thread.IsValid())
{
CMICmnMIValueTuple miTuple;
- if (!rSessionInfo.MIResponseFormThreadInfo3(m_cmdData, thread, miTuple))
+ if (!rSessionInfo.MIResponseFormThreadInfo(m_cmdData, thread, CMICmnLLDBDebugSessionInfo::eThreadInfoFormat_AllFrames, miTuple))
return MIstatus::failure;
m_vecMIValueTuple.push_back(miTuple);
@@ -151,7 +141,7 @@ CMICmdCmdThreadInfo::Acknowledge(void)
{
if (m_bSingleThread)
{
- if (!m_bThreadInvalid)
+ if (m_bThreadInvalid)
{
const CMICmnMIValueConst miValueConst("invalid thread id");
const CMICmnMIValueResult miValueResult("msg", miValueConst);
diff --git a/tools/lldb-mi/MICmdCmdThread.h b/tools/lldb-mi/MICmdCmdThread.h
index 59b6b124cce1..6b268f40e8eb 100644
--- a/tools/lldb-mi/MICmdCmdThread.h
+++ b/tools/lldb-mi/MICmdCmdThread.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdThread.h
-//
// Overview: CMICmdCmdThreadInfo interface.
//
// To implement new MI commands derive a new command class from the command base
@@ -20,13 +17,6 @@
// 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
diff --git a/tools/lldb-mi/MICmdCmdTrace.cpp b/tools/lldb-mi/MICmdCmdTrace.cpp
index 4ee72d300cc4..c0d5fc920373 100644
--- a/tools/lldb-mi/MICmdCmdTrace.cpp
+++ b/tools/lldb-mi/MICmdCmdTrace.cpp
@@ -7,17 +7,7 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdCmdTrace.h b/tools/lldb-mi/MICmdCmdTrace.h
index efe8e50b5c98..c9a6f72a379a 100644
--- a/tools/lldb-mi/MICmdCmdTrace.h
+++ b/tools/lldb-mi/MICmdCmdTrace.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdTrace.h
-//
// Overview: CMICmdCmdTraceStatus interface.
//
// To implement new MI commands derive a new command class from the command base
@@ -20,13 +17,6 @@
// 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
diff --git a/tools/lldb-mi/MICmdCmdVar.cpp b/tools/lldb-mi/MICmdCmdVar.cpp
index e9568beb173c..8c4abbda1128 100644
--- a/tools/lldb-mi/MICmdCmdVar.cpp
+++ b/tools/lldb-mi/MICmdCmdVar.cpp
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdVar.cpp
-//
// Overview: CMICmdCmdVarCreate implementation.
// CMICmdCmdVarUpdate implementation.
// CMICmdCmdVarDelete implementation.
@@ -19,16 +16,10 @@
// 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/SBType.h"
#include "lldb/API/SBThread.h"
// In-house headers:
@@ -42,6 +33,7 @@
#include "MICmdArgValThreadGrp.h"
#include "MICmdArgValOptionLong.h"
#include "MICmdArgValOptionShort.h"
+#include "MICmdArgValPrintValues.h"
#include "MICmdArgValListOfN.h"
#include "MICmnLLDBProxySBValue.h"
#include "MICmnLLDBUtilSBValue.h"
@@ -186,11 +178,29 @@ CMICmdCmdVarCreate::Execute(void)
lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread();
m_nThreadId = thread.GetIndexID();
lldb::SBFrame frame = bCurrentFrame ? thread.GetSelectedFrame() : thread.GetFrameAtIndex(nFrame);
- lldb::SBValue value = frame.FindVariable(rStrExpression.c_str());
+ lldb::SBValue value;
+
+ if (rStrExpression[0] == '$')
+ {
+ const CMIUtilString rStrRegister(rStrExpression.substr(1).c_str());
+ value = frame.FindRegister(rStrRegister.c_str());
+ }
+ else
+ {
+ const bool bArgs = true;
+ const bool bLocals = true;
+ const bool bStatics = true;
+ const bool bInScopeOnly = false;
+ const lldb::SBValueList valueList = frame.GetVariables(bArgs, bLocals, bStatics, bInScopeOnly);
+ value = valueList.GetFirstValueByName(rStrExpression.c_str());
+ }
+
if (!value.IsValid())
value = frame.EvaluateExpression(rStrExpression.c_str());
- if (value.IsValid())
+
+ if (value.IsValid() && value.GetError().Success())
{
+ CompleteSBValue(value);
m_bValid = true;
m_nChildren = value.GetNumChildren();
m_strType = CMICmnLLDBUtilSBValue(value).GetTypeNameDisplay();
@@ -199,6 +209,12 @@ CMICmdCmdVarCreate::Execute(void)
CMICmnLLDBDebugSessionInfoVarObj varObj(rStrExpression, m_strVarName, value);
m_strValue = varObj.GetValueFormatted();
}
+ else
+ {
+ lldb::SBStream err;
+ if (value.GetError().GetDescription(err))
+ m_strValue = err.GetData();
+ }
return MIstatus::success;
}
@@ -239,7 +255,10 @@ CMICmdCmdVarCreate::Acknowledge(void)
return MIstatus::success;
}
- const CMICmnMIValueConst miValueConst(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_VARIABLE_CREATION_FAILED), m_strExpression.c_str()));
+ CMIUtilString strErrMsg(m_strValue);
+ if (m_strValue.empty())
+ strErrMsg = CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_VARIABLE_CREATION_FAILED), m_strExpression.c_str());
+ const CMICmnMIValueConst miValueConst(strErrMsg);
CMICmnMIValueResult miValueResult("msg", miValueConst);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
m_miResultRecord = miRecordResult;
@@ -261,6 +280,35 @@ CMICmdCmdVarCreate::CreateSelf(void)
return new CMICmdCmdVarCreate();
}
+//++ ------------------------------------------------------------------------------------
+// Details: Complete SBValue object and its children to get SBValue::GetValueDidChange
+// work.
+// Type: Method.
+// Args: vrwValue - (R) Value to update.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+void
+CMICmdCmdVarCreate::CompleteSBValue(lldb::SBValue &vrwValue)
+{
+ // Force a value to update
+ vrwValue.GetValueDidChange();
+
+ // And update its children
+ lldb::SBType valueType = vrwValue.GetType();
+ if (!valueType.IsPointerType() && !valueType.IsReferenceType())
+ {
+ const MIuint nChildren = vrwValue.GetNumChildren();
+ for (MIuint i = 0; i < nChildren; ++i)
+ {
+ lldb::SBValue member = vrwValue.GetChildAtIndex(i);
+ if (member.IsValid())
+ CompleteSBValue(member);
+ }
+ }
+}
+
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
@@ -273,12 +321,9 @@ CMICmdCmdVarCreate::CreateSelf(void)
// Throws: None.
//--
CMICmdCmdVarUpdate::CMICmdCmdVarUpdate(void)
- : m_eVarInfoFormat(CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_NoValues)
- , m_constStrArgPrintValues("print-values")
+ : m_constStrArgPrintValues("print-values")
, m_constStrArgName("name")
- , m_bValueChangedArrayType(false)
- , m_bValueChangedCompositeType(false)
- , m_bValueChangedNormalType(false)
+ , m_bValueChanged(false)
, m_miValueList(true)
{
// Command factory matches this name with that received from the stdin stream
@@ -311,7 +356,7 @@ CMICmdCmdVarUpdate::~CMICmdCmdVarUpdate(void)
bool
CMICmdCmdVarUpdate::ParseArgs(void)
{
- bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgPrintValues, false, true)));
+ bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValPrintValues(m_constStrArgPrintValues, false, true)));
bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValString(m_constStrArgName, true, true)));
return (bOk && ParseValidateCmdOptions());
}
@@ -328,9 +373,13 @@ CMICmdCmdVarUpdate::ParseArgs(void)
bool
CMICmdCmdVarUpdate::Execute(void)
{
- CMICMDBASE_GETOPTION(pArgPrintValues, Number, m_constStrArgPrintValues);
+ CMICMDBASE_GETOPTION(pArgPrintValues, PrintValues, m_constStrArgPrintValues);
CMICMDBASE_GETOPTION(pArgName, String, m_constStrArgName);
+ CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_NoValues;
+ if (pArgPrintValues->GetFound())
+ eVarInfoFormat = static_cast<CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e>(pArgPrintValues->GetValue());
+
const CMIUtilString &rVarObjName(pArgName->GetValue());
CMICmnLLDBDebugSessionInfoVarObj varObj;
if (!CMICmnLLDBDebugSessionInfoVarObj::VarObjGet(rVarObjName, varObj))
@@ -339,73 +388,18 @@ CMICmdCmdVarUpdate::Execute(void)
return MIstatus::failure;
}
- const MIuint nPrintValues = pArgPrintValues->GetValue();
- if (nPrintValues >= CMICmnLLDBDebugSessionInfo::kNumVariableInfoFormats)
- {
- SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str()));
+ lldb::SBValue &rValue = varObj.GetValue();
+ if (!ExamineSBValueForChange(rValue, m_bValueChanged))
return MIstatus::failure;
- }
- m_eVarInfoFormat = static_cast<CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e>(nPrintValues);
- 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())
+ if (m_bValueChanged)
{
- 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;
- }
- }
+ const bool bPrintValue((eVarInfoFormat == CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues) ||
+ (eVarInfoFormat == CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_SimpleValues && rValue.GetNumChildren() == 0));
+ const CMIUtilString strValue(bPrintValue ? varObj.GetValueFormatted() : "");
+ const CMIUtilString strInScope(rValue.IsInScope() ? "true" : "false");
+ return MIFormResponse(rVarObjName, bPrintValue ? strValue.c_str() : nullptr, strInScope);
}
return MIstatus::success;
@@ -423,57 +417,20 @@ CMICmdCmdVarUpdate::Execute(void)
bool
CMICmdCmdVarUpdate::Acknowledge(void)
{
- if (m_bValueChangedArrayType || m_bValueChangedNormalType)
+ if (m_bValueChanged)
{
- 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);
- if (m_eVarInfoFormat != CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_NoValues)
- {
- 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);
+ CMICmnMIValueResult miValueResult("changelist", m_miValueList);
+ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
m_miResultRecord = miRecordResult;
}
else
{
- // MI: "%s^done,changelist=[]"
+ // MI print "%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;
@@ -497,30 +454,34 @@ CMICmdCmdVarUpdate::CreateSelf(void)
// 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.
+// vpValue - (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)
+CMICmdCmdVarUpdate::MIFormResponse(const CMIUtilString &vrStrVarName, const char *const vpValue, 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);
+ const CMICmnMIValueResult miValueResult("name", miValueConst);
CMICmnMIValueTuple miValueTuple(miValueResult);
- const CMICmnMIValueConst miValueConst2(vrStrValue);
- CMICmnMIValueResult miValueResult2("value", miValueConst2);
- bool bOk = miValueTuple.Add(miValueResult2);
+ bool bOk = true;
+ if (vpValue != nullptr)
+ {
+ const CMICmnMIValueConst miValueConst2(vpValue);
+ const CMICmnMIValueResult miValueResult2("value", miValueConst2);
+ bOk = bOk && miValueTuple.Add(miValueResult2);
+ }
const CMICmnMIValueConst miValueConst3(vrStrScope);
- CMICmnMIValueResult miValueResult3("in_scope", miValueConst3);
+ const CMICmnMIValueResult miValueResult3("in_scope", miValueConst3);
bOk = bOk && miValueTuple.Add(miValueResult3);
const CMICmnMIValueConst miValueConst4("false");
- CMICmnMIValueResult miValueResult4("type_changed", miValueConst4);
+ const CMICmnMIValueResult miValueResult4("type_changed", miValueConst4);
bOk = bOk && miValueTuple.Add(miValueResult4);
const CMICmnMIValueConst miValueConst5("0");
- CMICmnMIValueResult miValueResult5("has_more", miValueConst5);
+ const CMICmnMIValueResult miValueResult5("has_more", miValueConst5);
bOk = bOk && miValueTuple.Add(miValueResult5);
bOk = bOk && m_miValueList.Add(miValueTuple);
@@ -528,74 +489,46 @@ CMICmdCmdVarUpdate::MIFormResponse(const CMIUtilString &vrStrVarName, const CMIU
}
//++ ------------------------------------------------------------------------------------
-// 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.
+// Details: Determine if the var object was changed.
// 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.
+// vrwbChanged - (W) True = The var object was changed,
+// False = It was not changed.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
-CMICmdCmdVarUpdate::ExamineSBValueForChange(const CMICmnLLDBDebugSessionInfoVarObj &vrVarObj, const bool vbIgnoreVarType, bool &vrwbChanged)
+CMICmdCmdVarUpdate::ExamineSBValueForChange(lldb::SBValue &vrwValue, bool &vrwbChanged)
{
- vrwbChanged = false;
-
- CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
- lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
- lldb::SBThread thread = sbProcess.GetSelectedThread();
- if (thread.GetNumFrames() == 0)
+ if (vrwValue.GetValueDidChange())
{
+ vrwbChanged = true;
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
+ lldb::SBType valueType = vrwValue.GetType();
+ if (!valueType.IsPointerType() && !valueType.IsReferenceType())
{
- CMICmnLLDBDebugSessionInfoVarObj varObjParent;
- if (CMICmnLLDBDebugSessionInfoVarObj::VarObjGet(strVarObjParentName, varObjParent))
- varExpression = CMIUtilString::Format("%s.%s", varObjParent.GetNameReal().c_str(), rExpression.c_str());
- else
+ const MIuint nChildren = vrwValue.GetNumChildren();
+ for (MIuint i = 0; i < nChildren; ++i)
{
- // 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 member = vrwValue.GetChildAtIndex(i);
+ if (!member.IsValid())
+ continue;
- 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))
+ if (member.GetValueDidChange())
{
- // Have a value change so update the var object
vrwbChanged = true;
- const CMICmnLLDBDebugSessionInfoVarObj varObj(rExpression, vrVarObj.GetName(), value, strVarObjParentName);
+ return MIstatus::success;
}
+ else if (ExamineSBValueForChange(member, vrwbChanged) && vrwbChanged)
+ // Handle composite types (i.e. struct or arrays)
+ return MIstatus::success;
}
}
+ vrwbChanged = false;
return MIstatus::success;
}
@@ -986,13 +919,14 @@ CMICmdCmdVarSetFormat::CreateSelf(void)
// Throws: None.
//--
CMICmdCmdVarListChildren::CMICmdCmdVarListChildren(void)
- : m_bValueValid(false)
- , m_nChildren(0)
- , m_constStrArgPrintValues("print-values")
+ : m_constStrArgPrintValues("print-values")
, m_constStrArgName("name")
- , m_constStrArgNoValues("no-values")
- , m_constStrArgAllValues("all-values")
- , m_constStrArgSimpleValues("simple-values")
+ , m_constStrArgFrom("from")
+ , m_constStrArgTo("to")
+ , m_bValueValid(false)
+ , m_nChildren(0)
+ , m_miValueList(true)
+ , m_bHasMore(false)
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "var-list-children";
@@ -1010,7 +944,6 @@ CMICmdCmdVarListChildren::CMICmdCmdVarListChildren(void)
//--
CMICmdCmdVarListChildren::~CMICmdCmdVarListChildren(void)
{
- m_vecMiValueResult.clear();
}
//++ ------------------------------------------------------------------------------------
@@ -1025,11 +958,10 @@ CMICmdCmdVarListChildren::~CMICmdCmdVarListChildren(void)
bool
CMICmdCmdVarListChildren::ParseArgs(void)
{
- bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgPrintValues, false, true)));
- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgNoValues, false, true)));
- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgAllValues, false, true)));
- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgSimpleValues, false, true)));
+ bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValPrintValues(m_constStrArgPrintValues, false, true)));
bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValString(m_constStrArgName, true, true)));
+ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrom, false, true)));
+ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgTo, false, true)));
return (bOk && ParseValidateCmdOptions());
}
@@ -1045,25 +977,14 @@ CMICmdCmdVarListChildren::ParseArgs(void)
bool
CMICmdCmdVarListChildren::Execute(void)
{
+ CMICMDBASE_GETOPTION(pArgPrintValues, PrintValues, m_constStrArgPrintValues);
CMICMDBASE_GETOPTION(pArgName, String, m_constStrArgName);
- CMICMDBASE_GETOPTION(pArgPrintValue, Number, m_constStrArgPrintValues);
- CMICMDBASE_GETOPTION(pArgNoValue, OptionLong, m_constStrArgNoValues);
- CMICMDBASE_GETOPTION(pArgAllValue, OptionLong, m_constStrArgAllValues);
- CMICMDBASE_GETOPTION(pArgSimpleValue, OptionLong, m_constStrArgSimpleValues);
+ CMICMDBASE_GETOPTION(pArgFrom, Number, m_constStrArgFrom);
+ CMICMDBASE_GETOPTION(pArgTo, Number, m_constStrArgTo);
- MIuint print_value = 0;
- if (pArgPrintValue->GetFound())
- {
- MIuint tmp = pArgPrintValue->GetValue();
- if (tmp <= 2)
- print_value = tmp;
- }
- else if (pArgNoValue->GetFound())
- print_value = 0; // no value
- else if (pArgAllValue->GetFound())
- print_value = 1; // all values
- else if (pArgSimpleValue->GetFound())
- print_value = 2; // simple values
+ CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_NoValues;
+ if (pArgPrintValues->GetFound())
+ eVarInfoFormat = static_cast<CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e>(pArgPrintValues->GetValue());
const CMIUtilString &rVarObjName(pArgName->GetValue());
CMICmnLLDBDebugSessionInfoVarObj varObj;
@@ -1073,18 +994,32 @@ CMICmdCmdVarListChildren::Execute(void)
return MIstatus::failure;
}
+ MIuint nFrom = 0;
+ MIuint nTo = UINT32_MAX;
+ if (pArgFrom->GetFound() && pArgTo->GetFound())
+ {
+ nFrom = pArgFrom->GetValue();
+ nTo = pArgTo->GetValue();
+ }
+ else if (pArgFrom->GetFound() || pArgTo->GetFound())
+ {
+ // Only from or to was specified but both are required
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_VARIABLE_CHILD_RANGE_INVALID), m_cmdData.strMiCmd.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++)
+ const MIuint nChildren = rValue.GetNumChildren();
+ m_bHasMore = nTo < nChildren;
+ nTo = std::min(nTo, nChildren);
+ m_nChildren = nFrom < nTo ? nTo - nFrom : 0;
+ for (MIuint i = nFrom; i < nTo; 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()));
@@ -1097,19 +1032,20 @@ CMICmdCmdVarListChildren::Execute(void)
CMICmnMIValueTuple miValueTuple(miValueResult);
const CMICmnMIValueConst miValueConst2(strExp);
const CMICmnMIValueResult miValueResult2("exp", miValueConst2);
- miValueTuple.Add(miValueResult2);
- const CMIUtilString strNumChild(CMIUtilString::Format("%d", nChildren));
+ bool bOk = miValueTuple.Add(miValueResult2);
+ const CMIUtilString strNumChild(CMIUtilString::Format("%u", nChildren));
const CMICmnMIValueConst miValueConst3(strNumChild);
const CMICmnMIValueResult miValueResult3("numchild", miValueConst3);
- miValueTuple.Add(miValueResult3);
+ bOk = bOk && miValueTuple.Add(miValueResult3);
const CMICmnMIValueConst miValueConst5(utilValue.GetTypeNameDisplay());
const CMICmnMIValueResult miValueResult5("type", miValueConst5);
- miValueTuple.Add(miValueResult5);
+ bOk = bOk && miValueTuple.Add(miValueResult5);
const CMICmnMIValueConst miValueConst6(strThreadId);
const CMICmnMIValueResult miValueResult6("thread-id", miValueConst6);
- miValueTuple.Add(miValueResult6);
+ bOk = bOk && miValueTuple.Add(miValueResult6);
// nChildren == 0 is used to check for simple values
- if ( (print_value == 2 && nChildren == 0) || (print_value == 1) )
+ if (eVarInfoFormat == CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues ||
+ (eVarInfoFormat == CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_SimpleValues && nChildren == 0))
{
// Varobj gets added to CMICmnLLDBDebugSessionInfoVarObj static container of varObjs
CMICmnLLDBDebugSessionInfoVarObj var(strExp, name, member, rVarObjName);
@@ -1117,14 +1053,15 @@ CMICmdCmdVarListChildren::Execute(void)
CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted(member, CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Natural));
const CMICmnMIValueConst miValueConst7(strValue);
const CMICmnMIValueResult miValueResult7("value", miValueConst7);
- miValueTuple.Add(miValueResult7);
+ bOk = bOk && miValueTuple.Add(miValueResult7);
}
const CMICmnMIValueConst miValueConst8("0");
const CMICmnMIValueResult miValueResult8("has_more", miValueConst8);
- miValueTuple.Add(miValueResult8);
+ bOk = bOk && miValueTuple.Add(miValueResult8);
const CMICmnMIValueResult miValueResult9("child", miValueTuple);
- m_vecMiValueResult.push_back(miValueResult9);
-
+ bOk = bOk && m_miValueList.Add(miValueResult9);
+ if (!bOk)
+ return MIstatus::failure;
}
return MIstatus::success;
@@ -1144,41 +1081,29 @@ CMICmdCmdVarListChildren::Acknowledge(void)
{
if (m_bValueValid)
{
- // MI print "%s^done,numchild=\"%u\",children=[]""
+ // MI print "%s^done,numchild=\"%u\",children=[%s],has_more=\"%d\""
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);
- }
+ bool bOk = MIstatus::success;
+ if (m_nChildren != 0)
+ bOk = bOk && miValueResult.Add("children", m_miValueList);
+ const CMIUtilString strHasMore(m_bHasMore ? "1" : "0");
+ const CMICmnMIValueConst miValueConst2(strHasMore);
+ bOk = bOk && miValueResult.Add("has_more", miValueConst2);
+ if (!bOk)
+ return MIstatus::failure;
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);
+ // MI print "%s^error,msg=\"variable invalid\""
+ 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;
@@ -1410,7 +1335,7 @@ CMICmdCmdVarInfoPathExpression::Execute(void)
return MIstatus::failure;
}
- const MIchar *pPathExpression = stream.GetData();
+ const char *pPathExpression = stream.GetData();
if (pPathExpression == nullptr)
{
// Build expression from what we do know
diff --git a/tools/lldb-mi/MICmdCmdVar.h b/tools/lldb-mi/MICmdCmdVar.h
index add2058c029b..b6b65726eb8a 100644
--- a/tools/lldb-mi/MICmdCmdVar.h
+++ b/tools/lldb-mi/MICmdCmdVar.h
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// File: MICmdCmdVar.h
-//
// Overview: CMICmdCmdVarCreate interface.
// CMICmdCmdVarUpdate interface.
// CMICmdCmdVarDelete interface.
@@ -28,13 +25,6 @@
// 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
@@ -72,9 +62,16 @@ class CMICmdCmdVarCreate : public CMICmdBase
virtual bool Execute(void);
virtual bool Acknowledge(void);
virtual bool ParseArgs(void);
+
+ // Overridden:
+ public:
// From CMICmnBase
/* dtor */ virtual ~CMICmdCmdVarCreate(void);
+ // Methods:
+ private:
+ void CompleteSBValue(lldb::SBValue &vrwValue);
+
// Attribute:
private:
CMIUtilString m_strVarName;
@@ -124,18 +121,14 @@ class CMICmdCmdVarUpdate : public CMICmdBase
// Methods:
private:
- bool ExamineSBValueForChange(const CMICmnLLDBDebugSessionInfoVarObj &vrVarObj, const bool vbIgnoreVarType, bool &vrwbChanged);
- bool MIFormResponse(const CMIUtilString &vrStrVarName, const CMIUtilString &vrStrValue, const CMIUtilString &vrStrScope);
+ bool ExamineSBValueForChange(lldb::SBValue &vrwValue, bool &vrwbChanged);
+ bool MIFormResponse(const CMIUtilString &vrStrVarName, const char *const vpValue, const CMIUtilString &vrStrScope);
// Attribute:
private:
- CMIUtilString m_strValueName;
- CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e m_eVarInfoFormat;
- const CMIUtilString m_constStrArgPrintValues; // Not handled by *this command
+ const CMIUtilString m_constStrArgPrintValues;
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
+ bool m_bValueChanged; // True = yes value changed, false = no change
CMICmnMIValueList m_miValueList;
};
@@ -267,20 +260,16 @@ class CMICmdCmdVarListChildren : public CMICmdBase
// 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;
const CMIUtilString m_constStrArgName;
- const CMIUtilString m_constStrArgNoValues;
- const CMIUtilString m_constStrArgAllValues;
- const CMIUtilString m_constStrArgSimpleValues;
+ const CMIUtilString m_constStrArgFrom;
+ const CMIUtilString m_constStrArgTo;
+ bool m_bValueValid; // True = yes SBValue object is valid, false = not valid
+ MIuint m_nChildren;
+ CMICmnMIValueList m_miValueList;
+ bool m_bHasMore;
};
//++ ============================================================================
diff --git a/tools/lldb-mi/MICmdCommands.cpp b/tools/lldb-mi/MICmdCommands.cpp
index 81d10e1ce559..90a5d651f2af 100644
--- a/tools/lldb-mi/MICmdCommands.cpp
+++ b/tools/lldb-mi/MICmdCommands.cpp
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
@@ -18,13 +15,6 @@
// 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"
@@ -37,11 +27,13 @@
#include "MICmdCmdFile.h"
#include "MICmdCmdGdbInfo.h"
#include "MICmdCmdGdbSet.h"
+#include "MICmdCmdGdbShow.h"
#include "MICmdCmdGdbThread.h"
#include "MICmdCmdMiscellanous.h"
#include "MICmdCmdStack.h"
#include "MICmdCmdSupportInfo.h"
#include "MICmdCmdSupportList.h"
+#include "MICmdCmdSymbol.h"
#include "MICmdCmdTarget.h"
#include "MICmdCmdThread.h"
#include "MICmdCmdTrace.h"
@@ -91,6 +83,7 @@ MICmnCommands::RegisterAll(void)
bOk &= Register<CMICmdCmdBreakInsert>();
bOk &= Register<CMICmdCmdDataDisassemble>();
bOk &= Register<CMICmdCmdDataEvaluateExpression>();
+ bOk &= Register<CMICmdCmdDataInfoLine>();
bOk &= Register<CMICmdCmdDataReadMemoryBytes>();
bOk &= Register<CMICmdCmdDataReadMemory>();
bOk &= Register<CMICmdCmdDataListRegisterNames>();
@@ -98,6 +91,8 @@ MICmnCommands::RegisterAll(void)
bOk &= Register<CMICmdCmdDataWriteMemory>();
bOk &= Register<CMICmdCmdEnablePrettyPrinting>();
bOk &= Register<CMICmdCmdEnvironmentCd>();
+ bOk &= Register<CMICmdCmdExecAbort>();
+ bOk &= Register<CMICmdCmdExecArguments>();
bOk &= Register<CMICmdCmdExecContinue>();
bOk &= Register<CMICmdCmdExecInterrupt>();
bOk &= Register<CMICmdCmdExecFinish>();
@@ -110,17 +105,24 @@ MICmnCommands::RegisterAll(void)
bOk &= Register<CMICmdCmdGdbExit>();
bOk &= Register<CMICmdCmdGdbInfo>();
bOk &= Register<CMICmdCmdGdbSet>();
+ bOk &= Register<CMICmdCmdGdbShow>();
bOk &= Register<CMICmdCmdGdbThread>();
bOk &= Register<CMICmdCmdInferiorTtySet>();
bOk &= Register<CMICmdCmdInterpreterExec>();
bOk &= Register<CMICmdCmdListThreadGroups>();
bOk &= Register<CMICmdCmdSource>();
bOk &= Register<CMICmdCmdStackInfoDepth>();
+ bOk &= Register<CMICmdCmdStackInfoFrame>();
bOk &= Register<CMICmdCmdStackListFrames>();
bOk &= Register<CMICmdCmdStackListArguments>();
bOk &= Register<CMICmdCmdStackListLocals>();
+ bOk &= Register<CMICmdCmdStackListVariables>();
+ bOk &= Register<CMICmdCmdStackSelectFrame>();
bOk &= Register<CMICmdCmdSupportListFeatures>();
+ bOk &= Register<CMICmdCmdSymbolListLines>();
bOk &= Register<CMICmdCmdTargetSelect>();
+ bOk &= Register<CMICmdCmdTargetAttach>();
+ bOk &= Register<CMICmdCmdTargetDetach>();
bOk &= Register<CMICmdCmdThreadInfo>();
bOk &= Register<CMICmdCmdVarAssign>();
bOk &= Register<CMICmdCmdVarCreate>();
diff --git a/tools/lldb-mi/MICmdCommands.h b/tools/lldb-mi/MICmdCommands.h
index 0e9d27714302..a99d09c8057a 100644
--- a/tools/lldb-mi/MICmdCommands.h
+++ b/tools/lldb-mi/MICmdCommands.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
diff --git a/tools/lldb-mi/MICmdData.cpp b/tools/lldb-mi/MICmdData.cpp
index 44aa3c25dcb8..faafaf52483d 100644
--- a/tools/lldb-mi/MICmdData.cpp
+++ b/tools/lldb-mi/MICmdData.cpp
@@ -7,17 +7,5 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
index 114e32b26336..d58de903a68f 100644
--- a/tools/lldb-mi/MICmdData.h
+++ b/tools/lldb-mi/MICmdData.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmdFactory.cpp b/tools/lldb-mi/MICmdFactory.cpp
index ba333e7e1d0d..3fe4062b7721 100644
--- a/tools/lldb-mi/MICmdFactory.cpp
+++ b/tools/lldb-mi/MICmdFactory.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -171,8 +159,8 @@ CMICmdFactory::IsValid(const CMIUtilString &vMiCmd) const
return false;
}
- const MIint nPos = vMiCmd.find(" ");
- if (nPos != (MIint)std::string::npos)
+ const size_t nPos = vMiCmd.find(" ");
+ if (nPos != std::string::npos)
bValid = false;
return bValid;
diff --git a/tools/lldb-mi/MICmdFactory.h b/tools/lldb-mi/MICmdFactory.h
index 7af4b34ad0e7..8ad64fb5eafe 100644
--- a/tools/lldb-mi/MICmdFactory.h
+++ b/tools/lldb-mi/MICmdFactory.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
diff --git a/tools/lldb-mi/MICmdInterpreter.cpp b/tools/lldb-mi/MICmdInterpreter.cpp
index 33db4b8196df..ce5d30e92316 100644
--- a/tools/lldb-mi/MICmdInterpreter.cpp
+++ b/tools/lldb-mi/MICmdInterpreter.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -117,8 +105,8 @@ CMICmdInterpreter::ValidateIsMi(const CMIUtilString &vTextLine, bool &vwbYesVali
m_miCmdData.Clear();
m_miCmdData.strMiCmd = vTextLine;
- // The following change m_miCmdData as valid parts are indentified
- vwbYesValid = (MiHasCmdTokenEndingHypthen(vTextLine) || MiHasCmdTokenEndingAlpha(vTextLine));
+ // The following change m_miCmdData as valid parts are identified
+ vwbYesValid = (MiHasCmdTokenEndingHyphen(vTextLine) || MiHasCmdTokenEndingAlpha(vTextLine));
vwbYesValid = vwbYesValid && MiHasCmd(vTextLine);
if (vwbYesValid)
{
@@ -162,11 +150,11 @@ CMICmdInterpreter::HasCmdFactoryGotMiCmd(const SMICmdData &vCmd) const
// Throws: None.
//--
bool
-CMICmdInterpreter::MiHasCmdTokenEndingHypthen(const CMIUtilString &vTextLine)
+CMICmdInterpreter::MiHasCmdTokenEndingHyphen(const CMIUtilString &vTextLine)
{
- // The hythen is mandatory
- const MIint nPos = vTextLine.find("-", 0);
- if ((nPos == (MIint)std::string::npos))
+ // The hyphen is mandatory
+ const size_t nPos = vTextLine.find("-", 0);
+ if ((nPos == std::string::npos))
return false;
if (MiHasCmdTokenPresent(vTextLine))
@@ -198,7 +186,7 @@ CMICmdInterpreter::MiHasCmdTokenEndingHypthen(const CMIUtilString &vTextLine)
bool
CMICmdInterpreter::MiHasCmdTokenEndingAlpha(const CMIUtilString &vTextLine)
{
- MIchar cChar = vTextLine[0];
+ char cChar = vTextLine[0];
MIuint i = 0;
while (::isdigit(cChar) != 0)
{
@@ -218,7 +206,7 @@ CMICmdInterpreter::MiHasCmdTokenEndingAlpha(const CMIUtilString &vTextLine)
//++ ------------------------------------------------------------------------------------
// Details: Does the command entered match the criteria for a MI command format.
-// Is the command token present before the hypen?
+// Is the command token present before the hyphen?
// Type: Method.
// Args: vTextLine - (R) Text data to interpret.
// Return: bool - True = yes command token present, false = token not present.
@@ -227,13 +215,13 @@ CMICmdInterpreter::MiHasCmdTokenEndingAlpha(const CMIUtilString &vTextLine)
bool
CMICmdInterpreter::MiHasCmdTokenPresent(const CMIUtilString &vTextLine)
{
- const MIint nPos = vTextLine.find("-", 0);
+ const size_t 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
+// Is a recognised 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.
@@ -245,11 +233,11 @@ CMICmdInterpreter::MiHasCmdTokenPresent(const CMIUtilString &vTextLine)
bool
CMICmdInterpreter::MiHasCmd(const CMIUtilString &vTextLine)
{
- MIint nPos = 0;
+ size_t nPos = 0;
if (m_miCmdData.bMIOldStyle)
{
char cChar = vTextLine[0];
- MIuint i = 0;
+ size_t i = 0;
while (::isdigit(cChar) != 0)
{
cChar = vTextLine[++i];
@@ -262,9 +250,9 @@ CMICmdInterpreter::MiHasCmd(const CMIUtilString &vTextLine)
}
bool bFoundCmd = false;
- const MIint nLen = vTextLine.length();
- const MIint nPos2 = vTextLine.find(" ", nPos);
- if (nPos2 != (MIint)std::string::npos)
+ const size_t nLen = vTextLine.length();
+ const size_t nPos2 = vTextLine.find(" ", nPos);
+ if (nPos2 != std::string::npos)
{
if (nPos2 == nLen)
return false;
diff --git a/tools/lldb-mi/MICmdInterpreter.h b/tools/lldb-mi/MICmdInterpreter.h
index cc06179de882..acb052289ba2 100644
--- a/tools/lldb-mi/MICmdInterpreter.h
+++ b/tools/lldb-mi/MICmdInterpreter.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -58,7 +46,7 @@ class CMICmdInterpreter : public CMICmnBase, public MI::ISingleton<CMICmdInterpr
void operator=(const CMICmdInterpreter &);
bool HasCmdFactoryGotMiCmd(const SMICmdData &vCmdData) const;
- bool MiHasCmdTokenEndingHypthen(const CMIUtilString &vTextLine);
+ bool MiHasCmdTokenEndingHyphen(const CMIUtilString &vTextLine);
bool MiHasCmdTokenEndingAlpha(const CMIUtilString &vTextLine);
bool MiHasCmd(const CMIUtilString &vTextLine);
bool MiHasCmdTokenPresent(const CMIUtilString &vTextLine);
diff --git a/tools/lldb-mi/MICmdInvoker.cpp b/tools/lldb-mi/MICmdInvoker.cpp
index c415fbaf18b5..ef957c53bd70 100644
--- a/tools/lldb-mi/MICmdInvoker.cpp
+++ b/tools/lldb-mi/MICmdInvoker.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdInvoker.h b/tools/lldb-mi/MICmdInvoker.h
index 09c20c909240..a03c2d36103a 100644
--- a/tools/lldb-mi/MICmdInvoker.h
+++ b/tools/lldb-mi/MICmdInvoker.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
diff --git a/tools/lldb-mi/MICmdMgr.cpp b/tools/lldb-mi/MICmdMgr.cpp
index 44778b55daf0..998a72f5d07e 100644
--- a/tools/lldb-mi/MICmdMgr.cpp
+++ b/tools/lldb-mi/MICmdMgr.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdMgr.h b/tools/lldb-mi/MICmdMgr.h
index f403e1778c96..a45ecb61a3ce 100644
--- a/tools/lldb-mi/MICmdMgr.h
+++ b/tools/lldb-mi/MICmdMgr.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
diff --git a/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.cpp b/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.cpp
index 9bd9e83e1e6b..3f2ccfd10ce6 100644
--- a/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.cpp
+++ b/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.h b/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.h
index b969af0dacb9..16b11e5d0f4b 100644
--- a/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.h
+++ b/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.h
@@ -6,18 +6,6 @@
// 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
diff --git a/tools/lldb-mi/MICmnBase.cpp b/tools/lldb-mi/MICmnBase.cpp
index fce6a1d25562..909393564da4 100644
--- a/tools/lldb-mi/MICmnBase.cpp
+++ b/tools/lldb-mi/MICmnBase.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
diff --git a/tools/lldb-mi/MICmnBase.h b/tools/lldb-mi/MICmnBase.h
index 01fdab4dd14f..d2e2bcdf10d2 100644
--- a/tools/lldb-mi/MICmnBase.h
+++ b/tools/lldb-mi/MICmnBase.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmnConfig.h b/tools/lldb-mi/MICmnConfig.h
index 830e2e3b562c..2e31fb629f6b 100644
--- a/tools/lldb-mi/MICmnConfig.h
+++ b/tools/lldb-mi/MICmnConfig.h
@@ -6,45 +6,13 @@
// 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
diff --git a/tools/lldb-mi/MICmnLLDBBroadcaster.cpp b/tools/lldb-mi/MICmnLLDBBroadcaster.cpp
index 2b563c64d65a..55927b691d77 100644
--- a/tools/lldb-mi/MICmnLLDBBroadcaster.cpp
+++ b/tools/lldb-mi/MICmnLLDBBroadcaster.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmnLLDBBroadcaster.h b/tools/lldb-mi/MICmnLLDBBroadcaster.h
index 62ca0542dbf1..469aae969b96 100644
--- a/tools/lldb-mi/MICmnLLDBBroadcaster.h
+++ b/tools/lldb-mi/MICmnLLDBBroadcaster.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp b/tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp
index 7f6d9d53811a..cff651dd4a57 100644
--- a/tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp
+++ b/tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp
@@ -7,19 +7,8 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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 <inttypes.h> // For PRIx64
#include "lldb/API/SBThread.h"
#ifdef _WIN32
#include <io.h> // For the ::_access()
@@ -51,6 +40,9 @@ CMICmnLLDBDebugSessionInfo::CMICmnLLDBDebugSessionInfo(void)
, m_currentSelectedThread(LLDB_INVALID_THREAD_ID)
, m_constStrSharedDataKeyWkDir("Working Directory")
, m_constStrSharedDataSolibPath("Solib Path")
+ , m_constStrPrintCharArrayAsString("Print CharArrayAsString")
+ , m_constStrPrintExpandAggregates("Print ExpandAggregates")
+ , m_constStrPrintAggregateFieldNames("Print AggregateFieldNames")
{
}
@@ -222,7 +214,8 @@ CMICmnLLDBDebugSessionInfo::RecordBrkPtInfoDelete(const MIuint vnBrkPtId)
// Throws: None.
//--
bool
-CMICmnLLDBDebugSessionInfo::GetThreadFrames(const SMICmdData &vCmdData, const MIuint vThreadIdx, CMIUtilString &vwrThreadFrames)
+CMICmnLLDBDebugSessionInfo::GetThreadFrames(const SMICmdData &vCmdData, const MIuint vThreadIdx, const FrameInfoFormat_e veFrameInfoFormat,
+ CMIUtilString &vwrThreadFrames)
{
lldb::SBThread thread = GetProcess().GetThreadByIndexID(vThreadIdx);
const uint32_t nFrames = thread.GetNumFrames();
@@ -236,113 +229,13 @@ CMICmnLLDBDebugSessionInfo::GetThreadFrames(const SMICmdData &vCmdData, const MI
}
// 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\"},
+ // "frame={level=\"%d\",addr=\"0x%016" PRIx64 "\",func=\"%s\",args=[%s],file=\"%s\",fullname=\"%s\",line=\"%d\"},frame={level=\"%d\",addr=\"0x%016" PRIx64 "\",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 = eVariableType_Arguments;
- if (!MIResponseFormVariableInfo(frame, maskVarTypes, eVariableInfoFormat_AllValues, 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 = GetProcess().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 = eVariableType_Arguments;
- if (!MIResponseFormVariableInfo2(frame, maskVarTypes, eVariableInfoFormat_AllValues, 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))
+ if (!MIResponseFormFrameInfo(thread, nLevel, veFrameInfoFormat, miValueTuple))
return MIstatus::failure;
const CMICmnMIValueResult miValueResult2("frame", miValueTuple);
@@ -470,78 +363,10 @@ CMICmnLLDBDebugSessionInfo::AccessPath(const CMIUtilString &vPath, bool &vwbYesA
//--
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)
+ const ThreadInfoFormat_e veThreadInfoFormat, 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));
@@ -555,11 +380,11 @@ CMICmnLLDBDebugSessionInfo::MIResponseFormThreadInfo3(const SMICmdData &vCmdData
return MIstatus::failure;
// Add "target-id"
- const MIchar *pThreadName = rThread.GetName();
+ const char *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::IsAllValidAlphaAndNumeric(pThreadName)); // 32 is arbitary number
+ const char *pThrdFmt = bHaveName ? "%s" : "Thread %d";
CMIUtilString strThread;
if (bHaveName)
strThread = CMIUtilString::Format(pThrdFmt, pThreadName);
@@ -571,64 +396,16 @@ CMICmnLLDBDebugSessionInfo::MIResponseFormThreadInfo3(const SMICmdData &vCmdData
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;
+ if (veThreadInfoFormat != eThreadInfoFormat_NoFrames)
+ {
+ CMIUtilString strFrames;
+ if (!GetThreadFrames(vCmdData, rThread.GetIndexID(), eFrameInfoFormat_AllArgumentsInSimpleForm, strFrames))
+ 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;
+ const CMICmnMIValueConst miValueConst3(strFrames, true);
+ if (!vwrMIValueTuple.Add(miValueConst3, false))
+ return MIstatus::failure;
+ }
// Add "state"
const CMICmnMIValueConst miValueConst4(strState);
@@ -639,48 +416,6 @@ CMICmnLLDBDebugSessionInfo::MIResponseFormThreadInfo2(const SMICmdData &vCmdData
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) Construed according to VariableType_e.
-// veVarInfoFormat - (R) The type of variable info that should be shown.
-// 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,
- const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList)
-{
- bool bOk = MIstatus::success;
- lldb::SBFrame &rFrame = const_cast<lldb::SBFrame &>(vrFrame);
-
- const bool bArg = (vMaskVarTypes & eVariableType_Arguments);
- const bool bLocals = (vMaskVarTypes & eVariableType_Locals);
- const bool bStatics = (vMaskVarTypes & eVariableType_Statics);
- const bool bInScopeOnly = (vMaskVarTypes & eVariableType_InScope);
- 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.
@@ -695,7 +430,9 @@ CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo2(const lldb::SBFrame &vrF
//--
bool
CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes,
- const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList)
+ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList,
+ const MIuint vnMaxDepth, /* = 10 */
+ const bool vbMarkArgs /* = false*/)
{
bool bOk = MIstatus::success;
lldb::SBFrame &rFrame = const_cast<lldb::SBFrame &>(vrFrame);
@@ -704,416 +441,100 @@ CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo(const lldb::SBFrame &vrFr
const bool bLocals = (vMaskVarTypes & eVariableType_Locals);
const bool bStatics = (vMaskVarTypes & eVariableType_Statics);
const bool bInScopeOnly = (vMaskVarTypes & eVariableType_InScope);
- 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, veVarInfoFormat, vwrMiValueList, nCurrentRecursiveDepth);
- }
-
+
+ // Handle arguments first
+ lldb::SBValueList listArg = rFrame.GetVariables(bArg, false, false, false);
+ bOk = bOk && MIResponseForVariableInfoInternal(veVarInfoFormat, vwrMiValueList, listArg, vnMaxDepth, true, vbMarkArgs);
+
+ // Handle remaining variables
+ lldb::SBValueList listVars = rFrame.GetVariables(false, bLocals, bStatics, bInScopeOnly);
+ bOk = bOk && MIResponseForVariableInfoInternal(veVarInfoFormat, vwrMiValueList, listVars, vnMaxDepth, false, vbMarkArgs);
+
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) Construed according to VariableType_e.
-// veVarInfoFormat - (R) The type of variable info that should be shown.
-// 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,
- const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList)
+CMICmnLLDBDebugSessionInfo::MIResponseForVariableInfoInternal(const VariableInfoFormat_e veVarInfoFormat,
+ CMICmnMIValueList &vwrMiValueList,
+ const lldb::SBValueList &vwrSBValueList,
+ const MIuint vnMaxDepth,
+ const bool vbIsArgs,
+ const bool vbMarkArgs)
{
bool bOk = MIstatus::success;
- lldb::SBFrame &rFrame = const_cast<lldb::SBFrame &>(vrFrame);
-
- const bool bArg = (vMaskVarTypes & eVariableType_Arguments);
- const bool bLocals = (vMaskVarTypes & eVariableType_Locals);
- const bool bStatics = (vMaskVarTypes & eVariableType_Statics);
- const bool bInScopeOnly = (vMaskVarTypes & eVariableType_InScope);
- const MIuint nMaxRecusiveDepth = 10;
- MIuint nCurrentRecursiveDepth = 0;
- lldb::SBValueList listArg = rFrame.GetVariables(bArg, bLocals, bStatics, bInScopeOnly);
- const MIuint nArgs = listArg.GetSize();
+ const MIuint nArgs = vwrSBValueList.GetSize();
for (MIuint i = 0; bOk && (i < nArgs); i++)
{
- lldb::SBValue value = listArg.GetValueAtIndex(i);
- bOk = GetVariableInfo2(nMaxRecusiveDepth, value, false, veVarInfoFormat, 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.
-// veVarInfoFormat - (R) The type of variable info that should be shown.
-// 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,
- const VariableInfoFormat_e veVarInfoFormat, 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)
+ CMICmnMIValueTuple miValueTuple;
+ lldb::SBValue value = vwrSBValueList.GetValueAtIndex(i);
+ const CMICmnMIValueConst miValueConst(value.GetName());
+ const CMICmnMIValueResult miValueResultName("name", miValueConst);
+ if (vbMarkArgs && vbIsArgs)
{
- 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));
+ const CMICmnMIValueConst miValueConstArg("1");
+ const CMICmnMIValueResult miValueResultArg("arg", miValueConstArg);
+ miValueTuple.Add(miValueResultArg);
}
- else
+ if (veVarInfoFormat != eVariableInfoFormat_NoValues)
{
- // Basic types
- switch (veVarInfoFormat)
+ miValueTuple.Add(miValueResultName); // name
+ if (veVarInfoFormat == eVariableInfoFormat_SimpleValues)
{
- case eVariableInfoFormat_NoValues:
- {
- const CMICmnMIValueConst miValueConst(utilValue.GetName());
- const CMICmnMIValueResult miValueResult("name", miValueConst);
- return vwrMiValueList.Add(miValueResult);
- }
- case eVariableInfoFormat_AllValues:
- case eVariableInfoFormat_SimpleValues:
- {
- 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);
- break;
- }
- default:
- break;
+ const CMICmnMIValueConst miValueConst3(value.GetTypeName());
+ const CMICmnMIValueResult miValueResult3("type", miValueConst3);
+ miValueTuple.Add(miValueResult3);
}
- return vwrMiValueList.Add(miValueTuple);
- }
- }
- else if (bIsPointerType && utilValue.IsChildCharType())
- {
- switch (veVarInfoFormat)
- {
- case eVariableInfoFormat_NoValues:
+ const MIuint nChildren = value.GetNumChildren();
+ const bool bIsPointerType = value.GetType().IsPointerType();
+ if (nChildren == 0 || // no children
+ (bIsPointerType && nChildren == 1) || // pointers
+ veVarInfoFormat == eVariableInfoFormat_AllValues) // show all values
{
- const CMICmnMIValueConst miValueConst(utilValue.GetName());
- const CMICmnMIValueResult miValueResult("name", miValueConst);
- return vwrMiValueList.Add(miValueResult);
- }
- case eVariableInfoFormat_AllValues:
- case eVariableInfoFormat_SimpleValues:
- {
- // 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())
+ CMIUtilString strValue;
+ if (GetVariableInfo(value, vnMaxDepth == 0, strValue))
{
- 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);
- }
+ const CMICmnMIValueConst miValueConst2(strValue.Escape().AddSlashes());
+ const CMICmnMIValueResult miValueResult2("value", miValueConst2);
+ miValueTuple.Add(miValueResult2);
}
- break;
}
- default:
- break;
+ vwrMiValueList.Add(miValueTuple);
+ continue;
}
- return vwrMiValueList.Add(miValueTuple);
- }
- else if (bIsPointerType)
- {
- if (vbIsChildValue)
+
+ if (vbMarkArgs)
{
- // 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));
+ // If we are printing names only with vbMarkArgs, we still need to add the name to the value tuple
+ miValueTuple.Add(miValueResultName); // name
+ vwrMiValueList.Add(miValueTuple);
}
else
{
- // Basic types
- switch (veVarInfoFormat)
- {
- case eVariableInfoFormat_NoValues:
- {
- const CMICmnMIValueConst miValueConst(utilValue.GetName());
- const CMICmnMIValueResult miValueResult("name", miValueConst);
- return vwrMiValueList.Add(miValueResult);
- }
- case eVariableInfoFormat_AllValues:
- case eVariableInfoFormat_SimpleValues:
- {
- 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);
- break;
- }
- default:
- break;
- }
- return vwrMiValueList.Add(miValueTuple);
+ // If we are printing name only then no need to put it in the tuple.
+ vwrMiValueList.Add(miValueResultName);
}
}
- else
- {
- switch (veVarInfoFormat)
- {
- case eVariableInfoFormat_NoValues:
- {
- const CMICmnMIValueConst miValueConst(utilValue.GetName());
- const CMICmnMIValueResult miValueResult("name", miValueConst);
- return vwrMiValueList.Add(miValueResult);
- }
- case eVariableInfoFormat_AllValues:
- case eVariableInfoFormat_SimpleValues:
- {
- // 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, veVarInfoFormat, 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);
- break;
- }
- default:
- break;
- }
- return vwrMiValueList.Add(miValueTuple);
- }
+ 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.
-// veVarInfoFormat - (R) The type of variable info that should be shown.
-// vwrMIValueList - (W) MI value list object.
-// vnDepth - (RW) The current recursive depth of this function.
-// // Return: MIstatus::success - Functional succeeded.
+// Args: vrValue - (R) LLDB value object.
+// vbInSimpleForm - (R) True = Get variable info in simple form (i.e. don't expand aggregates).
+// - False = Get variable info (and expand aggregates if any).
+// vwrStrValue t - (W) The string representatin of this value.
+// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
-CMICmnLLDBDebugSessionInfo::GetVariableInfo2(const MIuint vnMaxDepth, const lldb::SBValue &vrValue, const bool vbIsChildValue,
- const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList,
- MIuint &vrwnDepth)
+CMICmnLLDBDebugSessionInfo::GetVariableInfo(const lldb::SBValue &vrValue, const bool vbInSimpleForm, CMIUtilString &vwrStrValue)
{
- // *** 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
- switch (veVarInfoFormat)
- {
- case eVariableInfoFormat_NoValues:
- {
- const CMICmnMIValueConst miValueConst(utilValue.GetName());
- const CMICmnMIValueResult miValueResult("name", miValueConst);
- return vwrMiValueList.Add(miValueResult);
- }
- case eVariableInfoFormat_AllValues:
- case eVariableInfoFormat_SimpleValues:
- {
- 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);
- break;
- }
- default:
- break;
- }
- return vwrMiValueList.Add(miValueTuple);
- }
- }
- else if (utilValue.IsChildCharType())
- {
- switch (veVarInfoFormat)
- {
- case eVariableInfoFormat_NoValues:
- {
- const CMICmnMIValueConst miValueConst(utilValue.GetName());
- const CMICmnMIValueResult miValueResult("name", miValueConst);
- return vwrMiValueList.Add(miValueResult);
- }
- case eVariableInfoFormat_AllValues:
- case eVariableInfoFormat_SimpleValues:
- {
- // 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);
- }
- }
- break;
- }
- default:
- break;
- }
- return vwrMiValueList.Add(miValueTuple);
- }
- else
- {
- switch (veVarInfoFormat)
- {
- case eVariableInfoFormat_NoValues:
- {
- const CMICmnMIValueConst miValueConst(utilValue.GetName());
- const CMICmnMIValueResult miValueResult("name", miValueConst);
- return vwrMiValueList.Add(miValueResult);
- }
- case eVariableInfoFormat_AllValues:
- case eVariableInfoFormat_SimpleValues:
- {
- // 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, veVarInfoFormat, 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);
- break;
- }
- default:
- break;
- }
- return vwrMiValueList.Add(miValueTuple);
- }
+ const CMICmnLLDBUtilSBValue utilValue(vrValue, true, false);
+ const bool bExpandAggregates = vbInSimpleForm ? false : true;
+ vwrStrValue = utilValue.GetValue(bExpandAggregates);
+ return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
@@ -1122,13 +543,14 @@ CMICmnLLDBDebugSessionInfo::GetVariableInfo2(const MIuint vnMaxDepth, const lldb
// Type: Method.
// Args: vrThread - (R) LLDB thread object.
// vwrMIValueTuple - (W) MI value tuple object.
+// vArgInfo - (R) Args information in MI response form.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmnLLDBDebugSessionInfo::MIResponseFormFrameInfo(const lldb::SBThread &vrThread, const MIuint vnLevel,
- CMICmnMIValueTuple &vwrMiValueTuple)
+ const FrameInfoFormat_e veFrameInfoFormat, CMICmnMIValueTuple &vwrMiValueTuple)
{
lldb::SBThread &rThread = const_cast<lldb::SBThread &>(vrThread);
@@ -1141,15 +563,51 @@ CMICmnLLDBDebugSessionInfo::MIResponseFormFrameInfo(const lldb::SBThread &vrThre
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\"}"
+ // MI print "{level=\"0\",addr=\"0x%016" PRIx64 "\",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))
+ if (!vwrMiValueTuple.Add(miValueResult))
return MIstatus::failure;
+ const CMIUtilString strAddr(CMIUtilString::Format("0x%016" PRIx64, pc));
+ const CMICmnMIValueConst miValueConst2(strAddr);
+ const CMICmnMIValueResult miValueResult2("addr", miValueConst2);
+ if (!vwrMiValueTuple.Add(miValueResult2))
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst3(fnName);
+ const CMICmnMIValueResult miValueResult3("func", miValueConst3);
+ if (!vwrMiValueTuple.Add(miValueResult3))
+ return MIstatus::failure;
+ if (veFrameInfoFormat != eFrameInfoFormat_NoArguments)
+ {
+ CMICmnMIValueList miValueList(true);
+ const MIuint maskVarTypes = eVariableType_Arguments;
+ if (veFrameInfoFormat == eFrameInfoFormat_AllArgumentsInSimpleForm)
+ {
+ if (!MIResponseFormVariableInfo(frame, maskVarTypes, eVariableInfoFormat_AllValues, miValueList, 0))
+ return MIstatus::failure;
+ }
+ else
+ if (!MIResponseFormVariableInfo(frame, maskVarTypes, eVariableInfoFormat_AllValues, miValueList))
+ return MIstatus::failure;
- vwrMiValueTuple = miValueTuple;
+ const CMICmnMIValueResult miValueResult4("args", miValueList);
+ if (!vwrMiValueTuple.Add(miValueResult4))
+ return MIstatus::failure;
+ }
+ const CMICmnMIValueConst miValueConst5(fileName);
+ const CMICmnMIValueResult miValueResult5("file", miValueConst5);
+ if (!vwrMiValueTuple.Add(miValueResult5))
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst6(path);
+ const CMICmnMIValueResult miValueResult6("fullname", miValueConst6);
+ if (!vwrMiValueTuple.Add(miValueResult6))
+ return MIstatus::failure;
+ const CMIUtilString strLine(CMIUtilString::Format("%d", nLine));
+ const CMICmnMIValueConst miValueConst7(strLine);
+ const CMICmnMIValueResult miValueResult7("line", miValueConst7);
+ if (!vwrMiValueTuple.Add(miValueResult7))
+ return MIstatus::failure;
return MIstatus::success;
}
@@ -1177,17 +635,17 @@ CMICmnLLDBDebugSessionInfo::GetFrameInfo(const lldb::SBFrame &vrFrame, lldb::add
const MIuint nBytes = rFrame.GetLineEntry().GetFileSpec().GetPath(&pBuffer[0], sizeof(pBuffer));
MIunused(nBytes);
CMIUtilString strResolvedPath(&pBuffer[0]);
- const MIchar *pUnkwn = "??";
+ const char *pUnkwn = "??";
if (!ResolvePath(pUnkwn, strResolvedPath))
return MIstatus::failure;
vwPath = strResolvedPath;
vwPc = rFrame.GetPC();
- const MIchar *pFnName = rFrame.GetFunctionName();
+ const char *pFnName = rFrame.GetFunctionName();
vwFnName = (pFnName != nullptr) ? pFnName : pUnkwn;
- const MIchar *pFileName = rFrame.GetLineEntry().GetFileSpec().GetFilename();
+ const char *pFileName = rFrame.GetLineEntry().GetFileSpec().GetFilename();
vwFileName = (pFileName != nullptr) ? pFileName : pUnkwn;
vwnLine = rFrame.GetLineEntry().GetLine();
@@ -1199,101 +657,6 @@ CMICmnLLDBDebugSessionInfo::GetFrameInfo(const lldb::SBFrame &vrFrame, lldb::add
// 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.
@@ -1303,7 +666,7 @@ CMICmnLLDBDebugSessionInfo::MIResponseFormFrameInfo2(const lldb::addr_t vPc, con
bool
CMICmnLLDBDebugSessionInfo::MIResponseFormBrkPtFrameInfo(const SBrkPtInfo &vrBrkPtInfo, CMICmnMIValueTuple &vwrMiValueTuple)
{
- const CMIUtilString strAddr(CMIUtilString::Format("0x%08llx", vrBrkPtInfo.m_pc));
+ const CMIUtilString strAddr(CMIUtilString::Format("0x%016" PRIx64, vrBrkPtInfo.m_pc));
const CMICmnMIValueConst miValueConst2(strAddr);
const CMICmnMIValueResult miValueResult2("addr", miValueConst2);
if (!vwrMiValueTuple.Add(miValueResult2))
@@ -1343,7 +706,7 @@ CMICmnLLDBDebugSessionInfo::MIResponseFormBrkPtFrameInfo(const SBrkPtInfo &vrBrk
bool
CMICmnLLDBDebugSessionInfo::MIResponseFormBrkPtInfo(const SBrkPtInfo &vrBrkPtInfo, CMICmnMIValueTuple &vwrMiValueTuple)
{
- // MI print "=breakpoint-modified,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%08x\",
+ // MI print "=breakpoint-modified,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%016" PRIx64 "\",
// func=\"%s\",file=\"%s\",fullname=\"%s/%s\",line=\"%d\",times=\"%d\",original-location=\"%s\"}"
// "number="
@@ -1438,15 +801,17 @@ CMICmnLLDBDebugSessionInfo::GetBrkPtInfo(const lldb::SBBreakpoint &vBrkPt, SBrkP
lldb::SBBreakpointLocation brkPtLoc = rBrkPt.GetLocationAtIndex(0);
lldb::SBAddress brkPtAddr = brkPtLoc.GetAddress();
lldb::SBSymbolContext symbolCntxt = brkPtAddr.GetSymbolContext(lldb::eSymbolContextEverything);
- const MIchar *pUnkwn = "??";
+ const char *pUnkwn = "??";
lldb::SBModule rModule = symbolCntxt.GetModule();
- const MIchar *pModule = rModule.IsValid() ? rModule.GetFileSpec().GetFilename() : pUnkwn;
+ const char *pModule = rModule.IsValid() ? rModule.GetFileSpec().GetFilename() : pUnkwn;
MIunused(pModule);
- const MIchar *pFile = pUnkwn;
- const MIchar *pFn = pUnkwn;
- const MIchar *pFilePath = pUnkwn;
+ const char *pFile = pUnkwn;
+ const char *pFn = pUnkwn;
+ const char *pFilePath = pUnkwn;
size_t nLine = 0;
- const size_t nAddr = brkPtAddr.GetLoadAddress(GetTarget());
+ lldb::addr_t nAddr = brkPtAddr.GetLoadAddress(GetTarget());
+ if (nAddr == LLDB_INVALID_ADDRESS)
+ nAddr = brkPtAddr.GetFileAddress();
lldb::SBCompileUnit rCmplUnit = symbolCntxt.GetCompileUnit();
if (rCmplUnit.IsValid())
diff --git a/tools/lldb-mi/MICmnLLDBDebugSessionInfo.h b/tools/lldb-mi/MICmnLLDBDebugSessionInfo.h
index 2e592f1f43c6..e3e16cd2ca54 100644
--- a/tools/lldb-mi/MICmnLLDBDebugSessionInfo.h
+++ b/tools/lldb-mi/MICmnLLDBDebugSessionInfo.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -87,7 +75,7 @@ class CMICmnLLDBDebugSessionInfo : public CMICmnBase, public MI::ISingleton<CMIC
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.
+ lldb::addr_t m_pc; // Address number.
CMIUtilString m_fnName; // Function name.
CMIUtilString m_fileName; // File name text.
CMIUtilString m_path; // Full file name and path text.
@@ -122,10 +110,28 @@ class CMICmnLLDBDebugSessionInfo : public CMICmnBase, public MI::ISingleton<CMIC
//--
enum VariableInfoFormat_e
{
- eVariableInfoFormat_NoValues,
- eVariableInfoFormat_AllValues,
- eVariableInfoFormat_SimpleValues,
- kNumVariableInfoFormats
+ eVariableInfoFormat_NoValues = 0,
+ eVariableInfoFormat_AllValues = 1,
+ eVariableInfoFormat_SimpleValues = 2
+ };
+
+ //++ ===================================================================
+ // Details: Determine the information that should be shown by using MIResponseFormThreadInfo family functions.
+ //--
+ enum ThreadInfoFormat_e
+ {
+ eThreadInfoFormat_NoFrames,
+ eThreadInfoFormat_AllFrames
+ };
+
+ //++ ===================================================================
+ // Details: Determine the information that should be shown by using MIResponseFormFrameInfo family functions.
+ //--
+ enum FrameInfoFormat_e
+ {
+ eFrameInfoFormat_NoArguments,
+ eFrameInfoFormat_AllArguments,
+ eFrameInfoFormat_AllArgumentsInSimpleForm
};
// Typedefs:
@@ -144,27 +150,15 @@ class CMICmnLLDBDebugSessionInfo : public CMICmnBase, public MI::ISingleton<CMIC
// 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 MIResponseFormFrameInfo(const lldb::SBThread &vrThread, const MIuint vnLevel,
+ const FrameInfoFormat_e veFrameInfoFormat, CMICmnMIValueTuple &vwrMiValueTuple);
+ bool MIResponseFormThreadInfo(const SMICmdData &vCmdData, const lldb::SBThread &vrThread,
+ const ThreadInfoFormat_e veThreadInfoFormat, CMICmnMIValueTuple &vwrMIValueTuple);
bool MIResponseFormVariableInfo(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes,
- const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList);
- bool MIResponseFormVariableInfo2(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes,
- const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList);
- bool MIResponseFormVariableInfo3(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes,
- const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList);
+ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList,
+ const MIuint vnMaxDepth = 10, const bool vbMarkArgs = false);
bool MIResponseFormBrkPtFrameInfo(const SBrkPtInfo &vrBrkPtInfo, CMICmnMIValueTuple &vwrMiValueTuple);
bool MIResponseFormBrkPtInfo(const SBrkPtInfo &vrBrkPtInfo, CMICmnMIValueTuple &vwrMiValueTuple);
bool GetBrkPtInfo(const lldb::SBBreakpoint &vBrkPt, SBrkPtInfo &vrwBrkPtInfo) const;
@@ -188,6 +182,9 @@ class CMICmnLLDBDebugSessionInfo : public CMICmnBase, public MI::ISingleton<CMIC
// Note: This list is expected to grow and will be moved and abstracted in the future.
const CMIUtilString m_constStrSharedDataKeyWkDir;
const CMIUtilString m_constStrSharedDataSolibPath;
+ const CMIUtilString m_constStrPrintCharArrayAsString;
+ const CMIUtilString m_constStrPrintExpandAggregates;
+ const CMIUtilString m_constStrPrintAggregateFieldNames;
// Typedefs:
private:
@@ -201,10 +198,13 @@ class CMICmnLLDBDebugSessionInfo : public CMICmnBase, public MI::ISingleton<CMIC
/* ctor */ CMICmnLLDBDebugSessionInfo(const CMICmnLLDBDebugSessionInfo &);
void operator=(const CMICmnLLDBDebugSessionInfo &);
//
- bool GetVariableInfo(const MIuint vnMaxDepth, const lldb::SBValue &vrValue, const bool vbIsChildValue,
- const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth);
- bool GetVariableInfo2(const MIuint vnMaxDepth, const lldb::SBValue &vrValue, const bool vbIsChildValue,
- const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth);
+ bool GetVariableInfo(const lldb::SBValue &vrValue, const bool vbInSimpleForm, CMIUtilString &vwrStrValue);
+ 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, const FrameInfoFormat_e veFrameInfoFormat,
+ CMIUtilString &vwrThreadFrames);
+ bool MIResponseForVariableInfoInternal(const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList,
+ const lldb::SBValueList &vwrSBValueList, const MIuint vnMaxDepth, const bool vbIsArgs, const bool vbMarkArgs);
// Overridden:
private:
diff --git a/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.cpp b/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.cpp
index c9abdd1cf90c..a42964c136cb 100644
--- a/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.cpp
+++ b/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.cpp
@@ -7,34 +7,23 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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[] = {
+const char *CMICmnLLDBDebugSessionInfoVarObj::ms_aVarFormatStrings[] = {
// CODETAG_SESSIONINFO_VARFORMAT_ENUM
// *** Order is import here.
"<Invalid var format>", "binary", "octal", "decimal", "hexadecimal", "natural"};
-const MIchar *CMICmnLLDBDebugSessionInfoVarObj::ms_aVarFormatChars[] = {
+const char *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
+CMICmnLLDBDebugSessionInfoVarObj::varFormat_e CMICmnLLDBDebugSessionInfoVarObj::ms_eDefaultFormat = eVarFormat_Natural;
//++ ------------------------------------------------------------------------------------
// Details: CMICmnLLDBDebugSessionInfoVarObj constructor.
@@ -234,7 +223,7 @@ CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForString(const CMIUtilString &vrS
// CODETAG_SESSIONINFO_VARFORMAT_ENUM
for (MIuint i = 0; i < eVarFormat_count; i++)
{
- const MIchar *pVarFormatString = ms_aVarFormatStrings[i];
+ const char *pVarFormatString = ms_aVarFormatStrings[i];
if (vrStrFormat == pVarFormatString)
return static_cast<varFormat_e>(i);
}
@@ -245,22 +234,22 @@ CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForString(const CMIUtilString &vrS
//++ ------------------------------------------------------------------------------------
// Details: Retrieve the var format enumeration for the specified character.
// Type: Static method.
-// Args: vrcFormat - (R) Character representing the var format.
+// Args: vcFormat - 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)
+CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForChar(char vcFormat)
{
- if ('r' == vrcFormat)
+ if ('r' == vcFormat)
return eVarFormat_Hex;
// CODETAG_SESSIONINFO_VARFORMAT_ENUM
for (MIuint i = 0; i < eVarFormat_count; i++)
{
- const MIchar *pVarFormatChar = ms_aVarFormatChars[i];
- if (*pVarFormatChar == vrcFormat)
+ const char *pVarFormatChar = ms_aVarFormatChars[i];
+ if (*pVarFormatChar == vcFormat)
return static_cast<varFormat_e>(i);
}
@@ -268,7 +257,9 @@ CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForChar(const MIchar &vrcFormat)
}
//++ ------------------------------------------------------------------------------------
-// Details: Return the equivalent var value formatted string for the given value type.
+// Details: Return the equivalent var value formatted string for the given value type,
+// which was prepared for printing (i.e. value was escaped and now it's ready
+// for wrapping into quotes).
// 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
@@ -283,21 +274,18 @@ 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
+ const CMICmnLLDBUtilSBValue utilValue(vrValue, true);
+ if (utilValue.IsIntegerType())
{
- // Composite variable type i.e. struct
- strFormattedValue = "{...}";
+ MIuint64 nValue = 0;
+ if (CMICmnLLDBProxySBValue::GetValueAsUnsigned(vrValue, nValue))
+ {
+ lldb::SBValue &rValue = const_cast<lldb::SBValue &>(vrValue);
+ return GetStringFormatted(nValue, rValue.GetValue(), veVarFormat);
+ }
}
- return strFormattedValue;
+ return utilValue.GetValue().Escape().AddSlashes();
}
//++ ------------------------------------------------------------------------------------
@@ -310,12 +298,17 @@ CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted(const lldb::SBValue &v
// Throws: None.
//--
CMIUtilString
-CMICmnLLDBDebugSessionInfoVarObj::GetStringFormatted(const MIuint64 vnValue, const MIchar *vpStrValueNatural,
+CMICmnLLDBDebugSessionInfoVarObj::GetStringFormatted(const MIuint64 vnValue, const char *vpStrValueNatural,
const CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat)
{
CMIUtilString strFormattedValue;
+ CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veFormat = veVarFormat;
+ if (ms_eDefaultFormat != eVarFormat_Invalid && veVarFormat == eVarFormat_Natural)
+ {
+ veFormat = ms_eDefaultFormat;
+ }
- switch (veVarFormat)
+ switch (veFormat)
{
case eVarFormat_Binary:
strFormattedValue = CMIUtilString::FormatBinary(vnValue);
@@ -434,6 +427,20 @@ CMICmnLLDBDebugSessionInfoVarObj::VarObjIdResetToZero(void)
}
//++ ------------------------------------------------------------------------------------
+// Details: Default format is globally used as the data format when "natural" is in effect, that is, this overrides the default
+// Type: Static method.
+// Args: None.
+// Returns: None.
+// Throws: None.
+//--
+void
+CMICmnLLDBDebugSessionInfoVarObj::VarObjSetFormat(varFormat_e eDefaultFormat)
+{
+ ms_eDefaultFormat = eDefaultFormat;
+}
+
+
+//++ ------------------------------------------------------------------------------------
// 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.
@@ -508,6 +515,19 @@ CMICmnLLDBDebugSessionInfoVarObj::GetValueFormatted(void) const
// Returns: lldb::SBValue & - LLDB Value object.
// Throws: None.
//--
+lldb::SBValue &
+CMICmnLLDBDebugSessionInfoVarObj::GetValue(void)
+{
+ return m_SBValue;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the LLDB Value object.
+// Type: Method.
+// Args: None.
+// Returns: lldb::SBValue & - Constant LLDB Value object.
+// Throws: None.
+//--
const lldb::SBValue &
CMICmnLLDBDebugSessionInfoVarObj::GetValue(void) const
{
@@ -543,7 +563,7 @@ CMICmnLLDBDebugSessionInfoVarObj::SetVarFormat(const varFormat_e veVarFormat)
void
CMICmnLLDBDebugSessionInfoVarObj::UpdateValue(void)
{
- m_strFormattedValue = CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted(m_SBValue, m_eVarFormat);
+ m_strFormattedValue = GetValueStringFormatted(m_SBValue, m_eVarFormat);
MIuint64 nValue = 0;
if (CMICmnLLDBProxySBValue::GetValueAsUnsigned(m_SBValue, nValue) == MIstatus::failure)
diff --git a/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.h b/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.h
index ecc960c85d0a..ad5a6ab680f2 100644
--- a/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.h
+++ b/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -69,7 +57,7 @@ class CMICmnLLDBDebugSessionInfoVarObj
// Statics:
public:
static varFormat_e GetVarFormatForString(const CMIUtilString &vrStrFormat);
- static varFormat_e GetVarFormatForChar(const MIchar &vrcFormat);
+ static varFormat_e GetVarFormatForChar(char vcFormat);
static CMIUtilString GetValueStringFormatted(const lldb::SBValue &vrValue, const varFormat_e veVarFormat);
static void VarObjAdd(const CMICmnLLDBDebugSessionInfoVarObj &vrVarObj);
static void VarObjDelete(const CMIUtilString &vrVarName);
@@ -79,6 +67,7 @@ class CMICmnLLDBDebugSessionInfoVarObj
static MIuint VarObjIdGet(void);
static void VarObjIdResetToZero(void);
static void VarObjClear(void);
+ static void VarObjSetFormat(varFormat_e eDefaultFormat);
// Methods:
public:
@@ -97,6 +86,7 @@ class CMICmnLLDBDebugSessionInfoVarObj
const CMIUtilString &GetName(void) const;
const CMIUtilString &GetNameReal(void) const;
const CMIUtilString &GetValueFormatted(void) const;
+ lldb::SBValue &GetValue(void);
const lldb::SBValue &GetValue(void) const;
varType_e GetType(void) const;
bool SetVarFormat(const varFormat_e veVarFormat);
@@ -115,7 +105,7 @@ class CMICmnLLDBDebugSessionInfoVarObj
// Statics:
private:
- static CMIUtilString GetStringFormatted(const MIuint64 vnValue, const MIchar *vpStrValueNatural, varFormat_e veVarFormat);
+ static CMIUtilString GetStringFormatted(const MIuint64 vnValue, const char *vpStrValueNatural, varFormat_e veVarFormat);
// Methods:
private:
@@ -124,10 +114,11 @@ class CMICmnLLDBDebugSessionInfoVarObj
// Attributes:
private:
- static const MIchar *ms_aVarFormatStrings[];
- static const MIchar *ms_aVarFormatChars[];
+ static const char *ms_aVarFormatStrings[];
+ static const char *ms_aVarFormatChars[];
static MapKeyToVarObj_t ms_mapVarIdToVarObj;
static MIuint ms_nVarUniqueId;
+ static varFormat_e ms_eDefaultFormat; // overrides "natural" format
//
// *** Upate the copy move constructors and assignment operator ***
varFormat_e m_eVarFormat;
diff --git a/tools/lldb-mi/MICmnLLDBDebugger.cpp b/tools/lldb-mi/MICmnLLDBDebugger.cpp
index 37ddda4db0ce..5d4a09a8a43b 100644
--- a/tools/lldb-mi/MICmnLLDBDebugger.cpp
+++ b/tools/lldb-mi/MICmnLLDBDebugger.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -234,6 +222,73 @@ CMICmnLLDBDebugger::GetDriver(void) const
}
//++ ------------------------------------------------------------------------------------
+// Details: Wait until all events have been handled.
+// This function works in pair with CMICmnLLDBDebugger::MonitorSBListenerEvents
+// that handles events from queue. When all events were handled and queue is
+// empty the MonitorSBListenerEvents notifies this function that it's ready to
+// go on. To synchronize them the m_mutexEventQueue and
+// m_conditionEventQueueEmpty are used.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void
+CMICmnLLDBDebugger::WaitForHandleEvent(void)
+{
+ std::unique_lock<std::mutex> lock(m_mutexEventQueue);
+
+ lldb::SBEvent event;
+ if (ThreadIsActive() && m_lldbListener.PeekAtNextEvent(event))
+ m_conditionEventQueueEmpty.wait(lock);
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check if need to rebroadcast stop event. This function will return true if
+// debugger is in synchronouse mode. In such case the
+// CMICmnLLDBDebugger::RebroadcastStopEvent should be called to rebroadcast
+// a new stop event (if any).
+// Type: Method.
+// Args: None.
+// Return: bool - True = Need to rebroadcast stop event, false = otherwise.
+// Throws: None.
+//--
+bool
+CMICmnLLDBDebugger::CheckIfNeedToRebroadcastStopEvent(void)
+{
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ if (!rSessionInfo.GetDebugger().GetAsync())
+ {
+ const bool include_expression_stops = false;
+ m_nLastStopId = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetStopID(include_expression_stops);
+ return true;
+ }
+
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Rebroadcast stop event if needed. This function should be called only if the
+// CMICmnLLDBDebugger::CheckIfNeedToRebroadcastStopEvent() returned true.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void
+CMICmnLLDBDebugger::RebroadcastStopEvent(void)
+{
+ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetProcess();
+ const bool include_expression_stops = false;
+ const uint32_t nStopId = process.GetStopID(include_expression_stops);
+ if (m_nLastStopId != nStopId)
+ {
+ lldb::SBEvent event = process.GetStopEventForStopID(nStopId);
+ process.GetBroadcaster().BroadcastEvent(event);
+ }
+}
+
+//++ ------------------------------------------------------------------------------------
// Details: Initialize the LLDB Debugger object.
// Type: Method.
// Args: None.
@@ -245,11 +300,15 @@ bool
CMICmnLLDBDebugger::InitSBDebugger(void)
{
m_lldbDebugger = lldb::SBDebugger::Create(false);
- if (m_lldbDebugger.IsValid())
- return MIstatus::success;
+ if (!m_lldbDebugger.IsValid())
+ {
+ SetErrorDescription(MIRSRC(IDS_LLDBDEBUGGER_ERR_INVALIDDEBUGGER));
+ return MIstatus::failure;
+ }
- SetErrorDescription(MIRSRC(IDS_LLDBDEBUGGER_ERR_INVALIDDEBUGGER));
- return MIstatus::failure;
+ m_lldbDebugger.GetCommandInterpreter().SetPromptOnQuit(false);
+
+ return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
@@ -275,7 +334,7 @@ CMICmnLLDBDebugger::InitStdStreams(void)
}
//++ ------------------------------------------------------------------------------------
-// Details: Set up the events from the SBDebugger's we would to listent to.
+// Details: Set up the events from the SBDebugger's we would like to listen to.
// Type: Method.
// Args: None.
// Return: MIstatus::success - Functionality succeeded.
@@ -293,7 +352,9 @@ CMICmnLLDBDebugger::InitSBListener(void)
}
const CMIUtilString strDbgId("CMICmnLLDBDebugger1");
- MIuint eventMask = lldb::SBTarget::eBroadcastBitBreakpointChanged;
+ MIuint eventMask = lldb::SBTarget::eBroadcastBitBreakpointChanged | lldb::SBTarget::eBroadcastBitModulesLoaded |
+ lldb::SBTarget::eBroadcastBitModulesUnloaded | lldb::SBTarget::eBroadcastBitWatchpointChanged |
+ lldb::SBTarget::eBroadcastBitSymbolsLoaded;
bool bOk = RegisterForEvent(strDbgId, CMIUtilString(lldb::SBTarget::GetBroadcasterClassName()), eventMask);
eventMask = lldb::SBThread::eBroadcastBitStackChanged;
@@ -306,7 +367,7 @@ CMICmnLLDBDebugger::InitSBListener(void)
eventMask = lldb::SBCommandInterpreter::eBroadcastBitQuitCommandReceived | lldb::SBCommandInterpreter::eBroadcastBitThreadShouldExit |
lldb::SBCommandInterpreter::eBroadcastBitAsynchronousOutputData |
lldb::SBCommandInterpreter::eBroadcastBitAsynchronousErrorData;
- bOk = bOk && RegisterForEvent(strDbgId, CMIUtilString(lldb::SBCommandInterpreter::GetBroadcasterClass()), eventMask);
+ bOk = bOk && RegisterForEvent(strDbgId, m_lldbDebugger.GetCommandInterpreter().GetBroadcaster(), eventMask);
return bOk;
}
@@ -332,7 +393,7 @@ CMICmnLLDBDebugger::RegisterForEvent(const CMIUtilString &vClientName, const CMI
if (!ClientSaveMask(vClientName, vBroadcasterClass, vEventMask))
return MIstatus::failure;
- const MIchar *pBroadCasterName = vBroadcasterClass.c_str();
+ const char *pBroadCasterName = vBroadcasterClass.c_str();
MIuint eventMask = vEventMask;
eventMask += existingMask;
const MIuint result = m_lldbListener.StartListeningForEventClass(m_lldbDebugger, pBroadCasterName, eventMask);
@@ -359,7 +420,7 @@ CMICmnLLDBDebugger::RegisterForEvent(const CMIUtilString &vClientName, const CMI
bool
CMICmnLLDBDebugger::RegisterForEvent(const CMIUtilString &vClientName, const lldb::SBBroadcaster &vBroadcaster, const MIuint vEventMask)
{
- const MIchar *pBroadcasterName = vBroadcaster.GetName();
+ const char *pBroadcasterName = vBroadcaster.GetName();
if (pBroadcasterName == nullptr)
{
SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME), MIRSRC(IDS_WORD_INVALIDNULLPTR)));
@@ -424,7 +485,7 @@ CMICmnLLDBDebugger::UnregisterForEvent(const CMIUtilString &vClientName, const C
}
}
- const MIchar *pBroadCasterName = vBroadcasterClass.c_str();
+ const char *pBroadCasterName = vBroadcasterClass.c_str();
if (!m_lldbListener.StopListeningForEventClass(m_lldbDebugger, pBroadCasterName, newEventMask))
{
SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_STOPLISTENER), vClientName.c_str(), pBroadCasterName));
@@ -626,7 +687,7 @@ CMICmnLLDBDebugger::ClientGetTheirMask(const CMIUtilString &vClientName, const C
vwEventMask = (*it).second;
}
- SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_CLIENTNOTREGISTERD), vClientName.c_str()));
+ SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_ERR_CLIENTNOTREGISTERED), vClientName.c_str()));
return MIstatus::failure;
}
@@ -635,7 +696,7 @@ CMICmnLLDBDebugger::ClientGetTheirMask(const CMIUtilString &vClientName, const C
// 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.
+// Out-of-band handler to further 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.
@@ -648,49 +709,48 @@ CMICmnLLDBDebugger::MonitorSBListenerEvents(bool &vrbIsAlive)
{
vrbIsAlive = true;
+ // Lock the mutex of event queue
+ // Note that it should be locked while we are in CMICmnLLDBDebugger::MonitorSBListenerEvents to
+ // avoid a race condition with CMICmnLLDBDebugger::WaitForHandleEvent
+ std::unique_lock<std::mutex> lock(m_mutexEventQueue);
+
lldb::SBEvent event;
const bool bGotEvent = m_lldbListener.GetNextEvent(event);
- if (!bGotEvent || !event.IsValid())
+ if (!bGotEvent)
{
+ // Notify that we are finished and unlock the mutex of event queue before sleeping
+ m_conditionEventQueueEmpty.notify_one();
+ lock.unlock();
+
+ // Wait a bit to reduce CPU load
const std::chrono::milliseconds time(1);
std::this_thread::sleep_for(time);
return MIstatus::success;
}
- if (!event.GetBroadcaster().IsValid())
- return MIstatus::success;
+ assert(event.IsValid());
+ assert(event.GetBroadcaster().IsValid());
// Debugging
m_pLog->WriteLog(CMIUtilString::Format("##### An event occurred: %s", event.GetBroadcasterClass()));
bool bHandledEvent = false;
- bool bExitAppEvent = false;
-
bool bOk = false;
{
// Lock Mutex before handling events so that we don't disturb a running cmd
CMIUtilThreadLock lock(CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex());
- bOk = CMICmnLLDBDebuggerHandleEvents::Instance().HandleEvent(event, bHandledEvent, bExitAppEvent);
+ bOk = CMICmnLLDBDebuggerHandleEvents::Instance().HandleEvent(event, bHandledEvent);
}
+
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;
+ return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
diff --git a/tools/lldb-mi/MICmnLLDBDebugger.h b/tools/lldb-mi/MICmnLLDBDebugger.h
index 403d71d0e32d..6c7e90006d8e 100644
--- a/tools/lldb-mi/MICmnLLDBDebugger.h
+++ b/tools/lldb-mi/MICmnLLDBDebugger.h
@@ -7,23 +7,12 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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 <condition_variable>
#include <map>
+#include <mutex>
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBListener.h"
#include "lldb/API/SBEvent.h"
@@ -60,6 +49,9 @@ class CMICmnLLDBDebugger : public CMICmnBase, public CMIUtilThreadActiveObjBase,
CMIDriverBase &GetDriver(void) const;
lldb::SBDebugger &GetTheDebugger(void);
lldb::SBListener &GetTheListener(void);
+ void WaitForHandleEvent(void);
+ bool CheckIfNeedToRebroadcastStopEvent(void);
+ void RebroadcastStopEvent(void);
// MI Commands can use these functions to listen for events they require
bool RegisterForEvent(const CMIUtilString &vClientName, const CMIUtilString &vBroadcasterClass, const MIuint vEventMask);
@@ -118,4 +110,7 @@ class CMICmnLLDBDebugger : public CMICmnBase, public CMIUtilThreadActiveObjBase,
const CMIUtilString m_constStrThisThreadId;
MapBroadcastClassNameToEventMask_t m_mapBroadcastClassNameToEventMask;
MapIdToEventMask_t m_mapIdToEventMask;
+ std::mutex m_mutexEventQueue;
+ std::condition_variable m_conditionEventQueueEmpty;
+ uint32_t m_nLastStopId;
};
diff --git a/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
index 50049e643ec7..49fce12739f8 100644
--- a/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
+++ b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
@@ -7,37 +7,28 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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/SBAddress.h"
#include "lldb/API/SBEvent.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBBreakpoint.h"
#include "lldb/API/SBStream.h"
+#include "lldb/API/SBTarget.h"
#include "lldb/API/SBThread.h"
#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBUnixSignals.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 "MICmnLLDBDebugger.h"
#include "MICmnLLDBDebugSessionInfo.h"
#include "MICmnMIResultRecord.h"
#include "MICmnMIValueConst.h"
@@ -47,6 +38,7 @@
#include "MICmnStreamStderr.h"
#include "MIUtilDebug.h"
#include "MIDriver.h"
+#include "Platform.h" // for PATH_MAX
//++ ------------------------------------------------------------------------------------
// Details: CMICmnLLDBDebuggerHandleEvents constructor.
@@ -88,6 +80,11 @@ CMICmnLLDBDebuggerHandleEvents::Initialize(void)
return MIstatus::success;
m_bInitialized = MIstatus::success;
+ m_bSignalsInitialized = false;
+ m_SIGINT = 0;
+ m_SIGSTOP = 0;
+ m_SIGSEGV = 0;
+ m_SIGTRAP = 0;
return m_bInitialized;
}
@@ -120,22 +117,20 @@ CMICmnLLDBDebuggerHandleEvents::Shutdown(void)
// 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)
+CMICmnLLDBDebuggerHandleEvents::HandleEvent(const lldb::SBEvent &vEvent, bool &vrbHandledEvent)
{
bool bOk = MIstatus::success;
vrbHandledEvent = false;
- vrbExitAppEvent = false;
if (lldb::SBProcess::EventIsProcessEvent(vEvent))
{
vrbHandledEvent = true;
- bOk = HandleEventSBProcess(vEvent, vrbExitAppEvent);
+ bOk = HandleEventSBProcess(vEvent);
}
else if (lldb::SBBreakpoint::EventIsBreakpointEvent(vEvent))
{
@@ -147,6 +142,16 @@ CMICmnLLDBDebuggerHandleEvents::HandleEvent(const lldb::SBEvent &vEvent, bool &v
vrbHandledEvent = true;
bOk = HandleEventSBThread(vEvent);
}
+ else if (lldb::SBTarget::EventIsTargetEvent(vEvent))
+ {
+ vrbHandledEvent = true;
+ bOk = HandleEventSBTarget(vEvent);
+ }
+ else if (lldb::SBCommandInterpreter::EventIsCommandInterpreterEvent(vEvent))
+ {
+ vrbHandledEvent = true;
+ bOk = HandleEventSBCommandInterpreter(vEvent);
+ }
return bOk;
}
@@ -155,17 +160,16 @@ CMICmnLLDBDebuggerHandleEvents::HandleEvent(const lldb::SBEvent &vEvent, bool &v
// 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)
+CMICmnLLDBDebuggerHandleEvents::HandleEventSBProcess(const lldb::SBEvent &vEvent)
{
bool bOk = MIstatus::success;
- const MIchar *pEventType = "";
+ const char *pEventType = "";
const MIuint nEventType = vEvent.GetType();
switch (nEventType)
{
@@ -177,7 +181,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBProcess(const lldb::SBEvent &vEvent
break;
case lldb::SBProcess::eBroadcastBitStateChanged:
pEventType = "eBroadcastBitStateChanged";
- bOk = HandleProcessEventBroadcastBitStateChanged(vEvent, vrbExitAppEvent);
+ bOk = HandleProcessEventBroadcastBitStateChanged(vEvent);
break;
case lldb::SBProcess::eBroadcastBitSTDERR:
pEventType = "eBroadcastBitSTDERR";
@@ -212,7 +216,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakPoint(const lldb::SBEvent &vEv
{
bool bOk = MIstatus::success;
- const MIchar *pEventType = "";
+ const char *pEventType = "";
const lldb::BreakpointEventType eEvent = lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(vEvent);
switch (eEvent)
{
@@ -239,6 +243,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakPoint(const lldb::SBEvent &vEv
break;
case lldb::eBreakpointEventTypeLocationsResolved:
pEventType = "eBreakpointEventTypeLocationsResolved";
+ bOk = HandleEventSBBreakpointCmn(vEvent);
break;
case lldb::eBreakpointEventTypeEnabled:
pEventType = "eBreakpointEventTypeEnabled";
@@ -335,7 +340,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointCmn(const lldb::SBEvent &
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\",
+ // MI print "=breakpoint-modified,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%016" PRIx64 "\",
// func=\"%s\",file=\"%s\",fullname=\"%s/%s\",line=\"%d\",times=\"%d\",original-location=\"%s\"}"
CMICmnMIValueTuple miValueTuple;
if (!rSessionInfo.MIResponseFormBrkPtInfo(sBrkPtInfo, miValueTuple))
@@ -413,7 +418,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointAdded(const lldb::SBEvent
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();
+ const char *pStrCondition = brkPt.GetCondition();
sBrkPtInfo.m_bCondition = (pStrCondition != nullptr) ? true : false;
sBrkPtInfo.m_strCondition = (pStrCondition != nullptr) ? pStrCondition : "??";
sBrkPtInfo.m_bBrkPtThreadId = (brkPt.GetThreadID() != 0) ? true : false;
@@ -431,7 +436,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointAdded(const lldb::SBEvent
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\"}"
+ // "=breakpoint-modified,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%016" PRIx64 "\",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);
@@ -453,7 +458,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointAdded(const lldb::SBEvent
}
// 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\"}"
+ // "=breakpoint-created,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%016" PRIx64 "\",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);
@@ -477,7 +482,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBThread(const lldb::SBEvent &vEvent)
return MIstatus::failure;
bool bOk = MIstatus::success;
- const MIchar *pEventType = "";
+ const char *pEventType = "";
const MIuint nEventType = vEvent.GetType();
switch (nEventType)
{
@@ -565,6 +570,172 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBThreadBitStackChanged(const lldb::S
}
//++ ------------------------------------------------------------------------------------
+// Details: Handle a LLDB SBTarget event.
+// Type: Method.
+// Args: vEvent - (R) An LLDB broadcast event.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool
+CMICmnLLDBDebuggerHandleEvents::HandleEventSBTarget(const lldb::SBEvent &vEvent)
+{
+ if (!ChkForStateChanges())
+ return MIstatus::failure;
+
+ bool bOk = MIstatus::success;
+ const char *pEventType = "";
+ const MIuint nEventType = vEvent.GetType();
+ switch (nEventType)
+ {
+ case lldb::SBTarget::eBroadcastBitBreakpointChanged:
+ pEventType = "eBroadcastBitBreakpointChanged";
+ break;
+ case lldb::SBTarget::eBroadcastBitModulesLoaded:
+ pEventType = "eBroadcastBitModulesLoaded";
+ bOk = HandleTargetEventBroadcastBitModulesLoaded(vEvent);
+ break;
+ case lldb::SBTarget::eBroadcastBitModulesUnloaded:
+ pEventType = "eBroadcastBitModulesUnloaded";
+ bOk = HandleTargetEventBroadcastBitModulesUnloaded(vEvent);
+ break;
+ case lldb::SBTarget::eBroadcastBitWatchpointChanged:
+ pEventType = "eBroadcastBitWatchpointChanged";
+ break;
+ case lldb::SBTarget::eBroadcastBitSymbolsLoaded:
+ pEventType = "eBroadcastBitSymbolsLoaded";
+ break;
+ default:
+ {
+ const CMIUtilString msg(CMIUtilString::Format(MIRSRC(IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT), "SBTarget", (MIuint)nEventType));
+ SetErrorDescription(msg);
+ return MIstatus::failure;
+ }
+ }
+ m_pLog->WriteLog(CMIUtilString::Format("##### An SBTarget event occurred: %s", pEventType));
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Print to stdout "=library-loaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded="%d"[,symbols-path=\"%s\"],loaded_addr=\"0x%016" PRIx64"\""
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmnLLDBDebuggerHandleEvents::HandleTargetEventBroadcastBitModulesLoaded(const lldb::SBEvent &vEvent)
+{
+ bool bOk = MIstatus::failure;
+ const MIuint nSize = lldb::SBTarget::GetNumModulesFromEvent(vEvent);
+ for (MIuint nIndex = 0; nIndex < nSize; ++nIndex)
+ {
+ const lldb::SBModule sbModule = lldb::SBTarget::GetModuleAtIndexFromEvent(nIndex, vEvent);
+ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleLoaded);
+ const bool bWithExtraFields = true;
+ bOk = MiHelpGetModuleInfo(sbModule, bWithExtraFields, miOutOfBandRecord);
+ bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord);
+ if (!bOk)
+ break;
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Print to stdout "=library-unloaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded="%d"[,symbols-path=\"%s\"],loaded_addr=\"0x%016" PRIx64"\""
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmnLLDBDebuggerHandleEvents::HandleTargetEventBroadcastBitModulesUnloaded(const lldb::SBEvent &vEvent)
+{
+ bool bOk = MIstatus::failure;
+ const MIuint nSize = lldb::SBTarget::GetNumModulesFromEvent(vEvent);
+ for (MIuint nIndex = 0; nIndex < nSize; ++nIndex)
+ {
+ const lldb::SBModule sbModule = lldb::SBTarget::GetModuleAtIndexFromEvent(nIndex, vEvent);
+ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleUnloaded);
+ const bool bWithExtraFields = false;
+ bOk = MiHelpGetModuleInfo(sbModule, bWithExtraFields, miOutOfBandRecord);
+ bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord);
+ if (!bOk)
+ break;
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Build module information for =library-loaded/=library-unloaded: "id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded="%d"[,symbols-path=\"%s\"],loaded_addr=\"0x%016" PRIx64"\""
+// Type: Method.
+// Args: vwrMiValueList - (W) MI value list object.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmnLLDBDebuggerHandleEvents::MiHelpGetModuleInfo(const lldb::SBModule &vModule, const bool vbWithExtraFields,
+ CMICmnMIOutOfBandRecord &vwrMiOutOfBandRecord)
+{
+ bool bOk = MIstatus::success;
+
+ // First, build standard fields:
+ // Build "id" field
+ std::unique_ptr<char[]> apPath(new char[PATH_MAX]);
+ vModule.GetFileSpec().GetPath(apPath.get(), PATH_MAX);
+ const CMIUtilString strTargetPath(apPath.get());
+ const CMICmnMIValueConst miValueConst(strTargetPath);
+ const CMICmnMIValueResult miValueResult("id", miValueConst);
+ bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult);
+ // Build "target-name" field
+ const CMICmnMIValueConst miValueConst2(strTargetPath);
+ const CMICmnMIValueResult miValueResult2("target-name", miValueConst2);
+ bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult2);
+ // Build "host-name" field
+ vModule.GetPlatformFileSpec().GetPath(apPath.get(), PATH_MAX);
+ const CMIUtilString strHostPath(apPath.get());
+ const CMICmnMIValueConst miValueConst3(strHostPath);
+ const CMICmnMIValueResult miValueResult3("host-name", miValueConst3);
+ bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult3);
+
+ // Then build extra fields if needed:
+ if (vbWithExtraFields)
+ {
+ // Build "symbols-loaded" field
+ vModule.GetSymbolFileSpec().GetPath(apPath.get(), PATH_MAX);
+ const CMIUtilString strSymbolsPath(apPath.get());
+ const bool bSymbolsLoaded = !CMIUtilString::Compare(strHostPath, strSymbolsPath);
+ const CMICmnMIValueConst miValueConst4(CMIUtilString::Format("%d", bSymbolsLoaded));
+ const CMICmnMIValueResult miValueResult4("symbols-loaded", miValueConst4);
+ bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult4);
+ // Build "symbols-path" field
+ if (bSymbolsLoaded)
+ {
+ const CMICmnMIValueConst miValueConst5(strSymbolsPath);
+ const CMICmnMIValueResult miValueResult5("symbols-path", miValueConst5);
+ bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult5);
+ }
+ // Build "loaded_addr" field
+ const lldb::SBAddress sbAddress(vModule.GetObjectFileHeaderAddress());
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ const lldb::addr_t nLoadAddress(sbAddress.GetLoadAddress(rSessionInfo.GetTarget()));
+ const CMIUtilString strLoadedAddr(nLoadAddress != LLDB_INVALID_ADDRESS ?
+ CMIUtilString::Format("0x%016" PRIx64, nLoadAddress) : "-");
+ const CMICmnMIValueConst miValueConst6(strLoadedAddr);
+ const CMICmnMIValueResult miValueResult6("loaded_addr", miValueConst6);
+ bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult6);
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
// Details: Handle a LLDB SBCommandInterpreter event.
// Type: Method.
// Args: vEvent - (R) An LLDB command interpreter event.
@@ -578,7 +749,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBCommandInterpreter(const lldb::SBEv
// This function is not used
// *** This function is under development
- const MIchar *pEventType = "";
+ const char *pEventType = "";
const MIuint nEventType = vEvent.GetType();
switch (nEventType)
{
@@ -596,8 +767,12 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBCommandInterpreter(const lldb::SBEv
pEventType = "eBroadcastBitResetPrompt";
break;
case lldb::SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
+ {
pEventType = "eBroadcastBitQuitCommandReceived";
+ const bool bForceExit = true;
+ CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag(bForceExit);
break;
+ }
case lldb::SBCommandInterpreter::eBroadcastBitAsynchronousOutputData:
pEventType = "eBroadcastBitAsynchronousOutputData";
break;
@@ -621,14 +796,17 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventSBCommandInterpreter(const lldb::SBEv
// 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)
+CMICmnLLDBDebuggerHandleEvents::HandleProcessEventBroadcastBitStateChanged(const lldb::SBEvent &vEvent)
{
+ // Make sure the program hasn't been auto-restarted:
+ if (lldb::SBProcess::GetRestartedFromEvent(vEvent))
+ return MIstatus::success;
+
bool bOk = ChkForStateChanges();
bOk = bOk && GetProcessStdout();
bOk = bOk && GetProcessStderr();
@@ -651,7 +829,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventBroadcastBitStateChanged(const
}
bool bShouldBrk = true;
- const MIchar *pEventType = "";
+ const char *pEventType = "";
switch (eEventState)
{
case lldb::eStateUnloaded:
@@ -668,7 +846,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventBroadcastBitStateChanged(const
break;
case lldb::eStateStopped:
pEventType = "eStateStopped";
- bOk = HandleProcessEventStateStopped(bShouldBrk);
+ bOk = HandleProcessEventStateStopped(vEvent, bShouldBrk);
if (bShouldBrk)
break;
case lldb::eStateCrashed:
@@ -687,8 +865,8 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventBroadcastBitStateChanged(const
pEventType = "eStateDetached";
break;
case lldb::eStateExited:
+ // Don't exit from lldb-mi here. We should be able to re-run target.
pEventType = "eStateExited";
- vrbExitAppEvent = true;
bOk = HandleProcessEventStateExited();
break;
default:
@@ -717,10 +895,6 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventBroadcastBitStateChanged(const
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().GetDebugger();
lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess();
@@ -761,12 +935,12 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateSuspended(const lldb::SBE
// Throws: None.
//--
bool
-CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateStopped(bool &vwrbShouldBrk)
+CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateStopped(const lldb::SBEvent &vrEvent, bool &vwrbShouldBrk)
{
if (!UpdateSelectedThread())
return MIstatus::failure;
- const MIchar *pEventType = "";
+ const char *pEventType = "";
bool bOk = MIstatus::success;
lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess();
const lldb::StopReason eStoppedReason = sbProcess.GetSelectedThread().GetStopReason();
@@ -792,10 +966,11 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateStopped(bool &vwrbShouldB
break;
case lldb::eStopReasonSignal:
pEventType = "eStopReasonSignal";
- bOk = HandleProcessEventStopSignal(vwrbShouldBrk);
+ bOk = HandleProcessEventStopSignal(vrEvent);
break;
case lldb::eStopReasonException:
pEventType = "eStopReasonException";
+ bOk = HandleProcessEventStopException();
break;
case lldb::eStopReasonExec:
pEventType = "eStopReasonExec";
@@ -821,111 +996,185 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateStopped(bool &vwrbShouldB
//++ ------------------------------------------------------------------------------------
// Details: Asynchronous event handler for LLDB Process stop signal.
// Type: Method.
-// Args: vwrbShouldBrk - (W) True = Yes break, false = do not.
+// Args: vrEvent - (R) An LLDB broadcast event.
// Return: MIstatus::success - Functionality succeeded.
// MIstatus::failure - Functionality failed.
// Throws: None.
//--
bool
-CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopSignal(bool &vwrbShouldBrk)
+CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopSignal(const lldb::SBEvent &vrEvent)
{
bool bOk = MIstatus::success;
+ InitializeSignals ();
lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess();
const MIuint64 nStopReason = sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0);
- switch (nStopReason)
+ const bool bInterrupted = lldb::SBProcess::GetInterruptedFromEvent(vrEvent);
+ if (nStopReason == m_SIGINT || (nStopReason == m_SIGSTOP && bInterrupted))
{
- 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", sbProcess.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 (sbProcess.IsValid())
- sbProcess.Continue();
- break;
- case 5: // Trace/breakpoint trap. SIGTRAP
+ // MI print "*stopped,reason=\"signal-received\",signal-name=\"SIGINT\",signal-meaning=\"Interrupt\",frame={%s},thread-id=\"%d\",stopped-threads=\"all\""
+ 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 miValueResult4("frame", miValueTuple);
+ bOk = bOk && miOutOfBandRecord.Add(miValueResult4);
+ const CMIUtilString strThreadId(CMIUtilString::Format("%" PRIu32, sbProcess.GetSelectedThread().GetIndexID()));
+ 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 && CMICmnStreamStdout::WritePrompt();
+ }
+ else if (nStopReason == m_SIGSTOP)
+ {
+ // MI print "*stopped,reason=\"signal-received\",signal-name=\"SIGSTOP\",signal-meaning=\"Stop\",frame={%s},thread-id=\"%d\",stopped-threads=\"all\""
+ const CMICmnMIValueConst miValueConst("signal-received");
+ const CMICmnMIValueResult miValueResult("reason", miValueConst);
+ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult);
+ const CMICmnMIValueConst miValueConst2("SIGSTOP");
+ const CMICmnMIValueResult miValueResult2("signal-name", miValueConst2);
+ bOk = miOutOfBandRecord.Add(miValueResult2);
+ const CMICmnMIValueConst miValueConst3("Stop");
+ const CMICmnMIValueResult miValueResult3("signal-meaning", miValueConst3);
+ bOk = bOk && miOutOfBandRecord.Add(miValueResult3);
+ CMICmnMIValueTuple miValueTuple;
+ bOk = bOk && MiHelpGetCurrentThreadFrame(miValueTuple);
+ const CMICmnMIValueResult miValueResult4("frame", miValueTuple);
+ bOk = bOk && miOutOfBandRecord.Add(miValueResult4);
+ const CMIUtilString strThreadId(CMIUtilString::Format("%" PRIu32, sbProcess.GetSelectedThread().GetIndexID()));
+ 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 && CMICmnStreamStdout::WritePrompt();
+ }
+ else if (nStopReason == m_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);
+ CMICmnMIValueTuple miValueTuple;
+ bOk = bOk && MiHelpGetCurrentThreadFrame(miValueTuple);
+ const CMICmnMIValueResult miValueResult4("frame", miValueTuple);
+ bOk = bOk && miOutOfBandRecord.Add(miValueResult4);
+ const CMIUtilString strThreadId(CMIUtilString::Format("%d", sbProcess.GetSelectedThread().GetIndexID()));
+ const CMICmnMIValueConst miValueConst5(strThreadId);
+ const CMICmnMIValueResult miValueResult5("thread-id", miValueConst5);
+ bOk = bOk && miOutOfBandRecord.Add(miValueResult5);
+ bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord);
+ // Note no "(gdb)" output here
+ }
+ else if (nStopReason == m_SIGTRAP)
+ {
+ lldb::SBThread thread = sbProcess.GetSelectedThread();
+ const MIuint nFrames = thread.GetNumFrames();
+ if (nFrames > 0)
{
- lldb::SBThread thread = sbProcess.GetSelectedThread();
- const MIuint nFrames = thread.GetNumFrames();
- if (nFrames > 0)
+ lldb::SBFrame frame = thread.GetFrameAtIndex(0);
+ const char *pFnName = frame.GetFunctionName();
+ if (pFnName != nullptr)
{
- 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))
{
- const CMIUtilString fnName = CMIUtilString(pFnName);
- static const CMIUtilString threadCloneFn = CMIUtilString("__pthread_clone");
-
- if (CMIUtilString::Compare(threadCloneFn, fnName))
- {
- if (sbProcess.IsValid())
- {
- sbProcess.Continue();
- vwrbShouldBrk = true;
- break;
- }
- }
+ if (sbProcess.IsValid())
+ sbProcess.Continue();
}
}
}
- default:
+ }
+ else
+ {
+ // MI print "*stopped,reason=\"signal-received\",signal-name=\"%s\",thread-id=\"%d\",stopped-threads=\"all\""
+ // MI print "*stopped,reason=\"signal-received\",signal=\"%d\",thread-id=\"%d\",stopped-threads=\"all\""
+ const CMICmnMIValueConst miValueConst("signal-received");
+ const CMICmnMIValueResult miValueResult("reason", miValueConst);
+ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult);
+ lldb::SBUnixSignals sbUnixSignals = sbProcess.GetUnixSignals();
+ const char *pSignal = sbUnixSignals.GetSignalAsCString(nStopReason);
+ if (pSignal)
{
- // 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 CMICmnMIValueConst miValueConst2(pSignal);
+ const CMICmnMIValueResult miValueResult2("signal-name", miValueConst2);
+ bOk = miOutOfBandRecord.Add(miValueResult2);
+ }
+ else
+ {
+ const CMIUtilString strSignal(CMIUtilString::Format("%" PRIu64, nStopReason));
+ const CMICmnMIValueConst miValueConst2(strSignal);
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 )
+ const CMIUtilString strThreadId(CMIUtilString::Format("%d", sbProcess.GetSelectedThread().GetIndexID()));
+ const CMICmnMIValueConst miValueConst3(strThreadId);
+ const CMICmnMIValueResult miValueResult3("thread-id", miValueConst3);
+ bOk = bOk && miOutOfBandRecord.Add(miValueResult3);
+ const CMICmnMIValueConst miValueConst4("all");
+ const CMICmnMIValueResult miValueResult4("stopped-threads", miValueConst4);
+ bOk = bOk && miOutOfBandRecord.Add(miValueResult4);
+ bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord);
+ bOk = bOk && CMICmnStreamStdout::WritePrompt();
+ }
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Asynchronous event handler for LLDB Process stop exception.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool
+CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopException(void)
+{
+ const lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess();
+ lldb::SBThread sbThread = sbProcess.GetSelectedThread();
+ const size_t nStopDescriptionLen = sbThread.GetStopDescription(nullptr, 0);
+ std::unique_ptr<char[]> apStopDescription(new char[nStopDescriptionLen]);
+ sbThread.GetStopDescription(apStopDescription.get(), nStopDescriptionLen);
+
+ // MI print "*stopped,reason=\"exception-received\",exception=\"%s\",thread-id=\"%d\",stopped-threads=\"all\""
+ const CMICmnMIValueConst miValueConst("exception-received");
+ const CMICmnMIValueResult miValueResult("reason", miValueConst);
+ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult);
+ const CMIUtilString strReason(apStopDescription.get());
+ const CMICmnMIValueConst miValueConst2(strReason);
+ const CMICmnMIValueResult miValueResult2("exception", miValueConst2);
+ bool bOk = miOutOfBandRecord.Add(miValueResult2);
+ const CMIUtilString strThreadId(CMIUtilString::Format("%d", sbThread.GetIndexID()));
+ const CMICmnMIValueConst miValueConst3(strThreadId);
+ const CMICmnMIValueResult miValueResult3("thread-id", miValueConst3);
+ bOk = bOk && miOutOfBandRecord.Add(miValueResult3);
+ const CMICmnMIValueConst miValueConst4("all");
+ const CMICmnMIValueResult miValueResult4("stopped-threads", miValueConst4);
+ bOk = bOk && miOutOfBandRecord.Add(miValueResult4);
+ bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord);
+ bOk = bOk && CMICmnStreamStdout::WritePrompt();
return bOk;
}
@@ -966,7 +1215,7 @@ CMICmnLLDBDebuggerHandleEvents::MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &
}
CMICmnMIValueTuple miValueTuple;
- if (!CMICmnLLDBDebugSessionInfo::Instance().MIResponseFormFrameInfo(thread, 0, miValueTuple))
+ if (!CMICmnLLDBDebugSessionInfo::Instance().MIResponseFormFrameInfo(thread, 0, CMICmnLLDBDebugSessionInfo::eFrameInfoFormat_NoArguments, miValueTuple))
{
SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_LLDBOUTOFBAND_ERR_FORM_MI_RESPONSE), "MiHelpGetCurrentThreadFrame()"));
return MIstatus::failure;
@@ -1045,26 +1294,14 @@ CMICmnLLDBDebuggerHandleEvents::MiStoppedAtBreakPoint(const MIuint64 vBrkPtId, c
const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6);
bOk = bOk && miOutOfBandRecord.Add(miValueResult6);
bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord);
- bOk = bOk && TextToStdout("(gdb)");
+ bOk = bOk && CMICmnStreamStdout::WritePrompt();
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;
- }
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
// 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\""
+ // "*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"%d\",frame={addr=\"0x%016" PRIx64 "\",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);
@@ -1076,15 +1313,11 @@ CMICmnLLDBDebuggerHandleEvents::MiStoppedAtBreakPoint(const MIuint64 vBrkPtId, c
CMICmnMIValueResult miValueResultB("bkptno", miValueConstB);
bOk = bOk && miOutOfBandRecord.Add(miValueResultB);
- // frame={addr=\"0x%08x\",func=\"%s\",args=[],file=\"%s\",fullname=\"%s\",line=\"%d\"}
+ // frame={addr=\"0x%016" PRIx64 "\",func=\"%s\",args=[],file=\"%s\",fullname=\"%s\",line=\"%d\"}
if (bOk)
{
- CMICmnMIValueList miValueList(true);
- const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments;
- bOk = rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues, miValueList);
-
CMICmnMIValueTuple miValueTuple;
- bOk = bOk && rSession.MIResponseFormFrameInfo2(pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple);
+ bOk = bOk && rSessionInfo.MIResponseFormFrameInfo(thread, 0, CMICmnLLDBDebugSessionInfo::eFrameInfoFormat_AllArguments, miValueTuple);
const CMICmnMIValueResult miValueResult8("frame", miValueTuple);
bOk = bOk && miOutOfBandRecord.Add(miValueResult8);
}
@@ -1103,7 +1336,7 @@ CMICmnLLDBDebuggerHandleEvents::MiStoppedAtBreakPoint(const MIuint64 vBrkPtId, c
const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9);
bOk = miOutOfBandRecord.Add(miValueResult9);
bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord);
- bOk = bOk && TextToStdout("(gdb)");
+ bOk = bOk && CMICmnStreamStdout::WritePrompt();
}
return MIstatus::success;
@@ -1134,33 +1367,18 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonTrace(void)
const CMICmnMIValueResult miValueResult2("stopped-threads", miValueConst2);
bOk = miOutOfBandRecord.Add(miValueResult2);
bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord);
- bOk = bOk && TextToStdout("(gdb)");
+ bOk = bOk && CMICmnStreamStdout::WritePrompt();
return bOk;
}
- CMICmnLLDBDebugSessionInfo &rSession = CMICmnLLDBDebugSessionInfo::Instance();
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(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;
- }
+ // "*stopped,reason=\"end-stepping-range\",frame={addr=\"0x%016" PRIx64 "\",func=\"%s\",args=[\"%s\"],file=\"%s\",fullname=\"%s\",line=\"%d\"},thread-id=\"%d\",stopped-threads=\"all\""
// Function args
- CMICmnMIValueList miValueList(true);
- const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments;
- if (!rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues, miValueList))
- return MIstatus::failure;
CMICmnMIValueTuple miValueTuple;
- if (!rSession.MIResponseFormFrameInfo2(pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple))
+ if (!rSessionInfo.MIResponseFormFrameInfo(thread, 0, CMICmnLLDBDebugSessionInfo::eFrameInfoFormat_AllArguments, miValueTuple))
return MIstatus::failure;
const CMICmnMIValueConst miValueConst("end-stepping-range");
@@ -1183,7 +1401,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonTrace(void)
const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9);
bOk = miOutOfBandRecord.Add(miValueResult9);
bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord);
- bOk = bOk && TextToStdout("(gdb)");
+ bOk = bOk && CMICmnStreamStdout::WritePrompt();
}
return bOk;
@@ -1275,7 +1493,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateRunning(void)
CMICmnMIValueResult miValueResult("thread-id", miValueConst);
CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult);
bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord);
- bOk = bOk && TextToStdout("(gdb)");
+ bOk = bOk && CMICmnStreamStdout::WritePrompt();
return bOk;
}
@@ -1319,7 +1537,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateExited(void)
CMICmnMIOutOfBandRecord miOutOfBandRecord3(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult4);
bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord3);
}
- bOk = bOk && TextToStdout("(gdb)");
+ bOk = bOk && CMICmnStreamStdout::WritePrompt();
return bOk;
}
@@ -1337,26 +1555,44 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateExited(void)
bool
CMICmnLLDBDebuggerHandleEvents::GetProcessStdout(void)
{
- bool bOk = MIstatus::success;
-
- char c;
- size_t nBytes = 0;
CMIUtilString text;
+ std::unique_ptr<char[]> apStdoutBuffer(new char[1024]);
lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess();
- while (process.GetSTDOUT(&c, 1) > 0)
- {
- CMIUtilString str;
- if (ConvertPrintfCtrlCodeToString(c, str))
- text += str;
- nBytes++;
- }
- if (nBytes > 0)
+ while (1)
{
- const CMIUtilString t(CMIUtilString::Format("~\"%s\"", text.c_str()));
- bOk = TextToStdout(t);
+ const size_t nBytes = process.GetSTDOUT(apStdoutBuffer.get(), 1024);
+ text.append(apStdoutBuffer.get(), nBytes);
+
+ while (1)
+ {
+ const size_t nNewLine = text.find('\n');
+ if (nNewLine == std::string::npos)
+ break;
+
+ const CMIUtilString line(text.substr(0, nNewLine + 1).c_str());
+ text.erase(0, nNewLine + 1);
+ const bool bEscapeQuotes(true);
+ CMICmnMIValueConst miValueConst(line.Escape(bEscapeQuotes));
+ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, miValueConst);
+ const bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord);
+ if (!bOk)
+ return MIstatus::failure;
+ }
+
+ if (nBytes == 0)
+ {
+ if (!text.empty())
+ {
+ const bool bEscapeQuotes(true);
+ CMICmnMIValueConst miValueConst(text.Escape(bEscapeQuotes));
+ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, miValueConst);
+ return MiOutOfBandRecordToStdout(miOutOfBandRecord);
+ }
+ break;
+ }
}
- return bOk;
+ return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
@@ -1372,69 +1608,40 @@ CMICmnLLDBDebuggerHandleEvents::GetProcessStdout(void)
bool
CMICmnLLDBDebuggerHandleEvents::GetProcessStderr(void)
{
- bool bOk = MIstatus::success;
-
- char c;
- size_t nBytes = 0;
CMIUtilString text;
+ std::unique_ptr<char[]> apStderrBuffer(new char[1024]);
lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess();
- while (process.GetSTDERR(&c, 1) > 0)
+ while (1)
{
- CMIUtilString str;
- if (ConvertPrintfCtrlCodeToString(c, str))
- text += str;
- nBytes++;
- }
- if (nBytes > 0)
- {
- const CMIUtilString t(CMIUtilString::Format("~\"%s\"", text.c_str()));
- bOk = TextToStdout(t);
- }
+ const size_t nBytes = process.GetSTDERR(apStderrBuffer.get(), 1024);
+ text.append(apStderrBuffer.get(), nBytes);
- return bOk;
-}
+ while (1)
+ {
+ const size_t nNewLine = text.find('\n');
+ if (nNewLine == std::string::npos)
+ break;
-//++ ------------------------------------------------------------------------------------
-// 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);
+ const CMIUtilString line(text.substr(0, nNewLine + 1).c_str());
+ const bool bEscapeQuotes(true);
+ CMICmnMIValueConst miValueConst(line.Escape(bEscapeQuotes));
+ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, miValueConst);
+ const bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord);
+ if (!bOk)
+ return MIstatus::failure;
+ }
+
+ if (nBytes == 0)
+ {
+ if (!text.empty())
+ {
+ const bool bEscapeQuotes(true);
+ CMICmnMIValueConst miValueConst(text.Escape(bEscapeQuotes));
+ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, miValueConst);
+ return MiOutOfBandRecordToStdout(miOutOfBandRecord);
+ }
break;
+ }
}
return MIstatus::success;
@@ -1451,14 +1658,10 @@ CMICmnLLDBDebuggerHandleEvents::ConvertPrintfCtrlCodeToString(const MIchar vCtrl
bool
CMICmnLLDBDebuggerHandleEvents::ChkForStateChanges(void)
{
- lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess();
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
if (!sbProcess.IsValid())
return MIstatus::success;
- lldb::SBTarget sbTarget = CMICmnLLDBDebugSessionInfo::Instance().GetTarget();
- if (!sbTarget.IsValid())
- return MIstatus::success;
-
- bool bOk = MIstatus::success;
// Check for created threads
const MIuint nThread = sbProcess.GetNumThreads();
@@ -1470,33 +1673,20 @@ CMICmnLLDBDebuggerHandleEvents::ChkForStateChanges(void)
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;
- }
+ const MIuint threadIndexID = thread.GetIndexID();
+ const bool bFound = std::find(rSessionInfo.m_vecActiveThreadId.cbegin(), rSessionInfo.m_vecActiveThreadId.cend(), threadIndexID) != rSessionInfo.m_vecActiveThreadId.end();
if (!bFound)
{
- CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.push_back(i);
+ rSessionInfo.m_vecActiveThreadId.push_back(threadIndexID);
// Form MI "=thread-created,id=\"%d\",group-id=\"i1\""
- const CMIUtilString strValue(CMIUtilString::Format("%d", thread.GetIndexID()));
+ const CMIUtilString strValue(CMIUtilString::Format("%d", threadIndexID));
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);
+ bool bOk = miOutOfBand.Add(miValueResult2);
bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBand);
if (!bOk)
return MIstatus::failure;
@@ -1506,13 +1696,13 @@ CMICmnLLDBDebuggerHandleEvents::ChkForStateChanges(void)
lldb::SBThread currentThread = sbProcess.GetSelectedThread();
if (currentThread.IsValid())
{
- const MIuint threadId = currentThread.GetIndexID();
- if (CMICmnLLDBDebugSessionInfo::Instance().m_currentSelectedThread != threadId)
+ const MIuint currentThreadIndexID = currentThread.GetIndexID();
+ if (rSessionInfo.m_currentSelectedThread != currentThreadIndexID)
{
- CMICmnLLDBDebugSessionInfo::Instance().m_currentSelectedThread = threadId;
+ rSessionInfo.m_currentSelectedThread = currentThreadIndexID;
// Form MI "=thread-selected,id=\"%d\""
- const CMIUtilString strValue(CMIUtilString::Format("%d", currentThread.GetIndexID()));
+ const CMIUtilString strValue(CMIUtilString::Format("%d", currentThreadIndexID));
const CMICmnMIValueConst miValueConst(strValue);
const CMICmnMIValueResult miValueResult("id", miValueConst);
CMICmnMIOutOfBandRecord miOutOfBand(CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, miValueResult);
@@ -1522,31 +1712,34 @@ CMICmnLLDBDebuggerHandleEvents::ChkForStateChanges(void)
}
// Check for invalid (removed) threads
- CMICmnLLDBDebugSessionInfo::VecActiveThreadId_t::const_iterator it = CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.begin();
- while (it != CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.end())
+ CMICmnLLDBDebugSessionInfo::VecActiveThreadId_t::iterator it = rSessionInfo.m_vecActiveThreadId.begin();
+ while (it != rSessionInfo.m_vecActiveThreadId.end())
{
- const MIuint nThreadId = *it;
- lldb::SBThread thread = sbProcess.GetThreadAtIndex(nThreadId);
+ const MIuint threadIndexID = *it;
+ lldb::SBThread thread = sbProcess.GetThreadByIndexID(threadIndexID);
if (!thread.IsValid())
{
// Form MI "=thread-exited,id=\"%ld\",group-id=\"i1\""
- const CMIUtilString strValue(CMIUtilString::Format("%ld", thread.GetIndexID()));
+ const CMIUtilString strValue(CMIUtilString::Format("%ld", threadIndexID));
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);
+ bool bOk = miOutOfBand.Add(miValueResult2);
bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBand);
if (!bOk)
return MIstatus::failure;
- }
- // Next
- ++it;
+ // Remove current thread from cache and get next
+ it = rSessionInfo.m_vecActiveThreadId.erase(it);
+ }
+ else
+ // Next
+ ++it;
}
- return TextToStdout("(gdb)");
+ return CMICmnStreamStdout::WritePrompt();
}
//++ ------------------------------------------------------------------------------------
@@ -1608,3 +1801,29 @@ CMICmnLLDBDebuggerHandleEvents::TextToStderr(const CMIUtilString &vrTxt)
{
return CMICmnStreamStderr::TextToStderr(vrTxt);
}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize the member variables with the signal values in this process
+// file.
+// Type: Method.
+// Args: None
+// Return: Noen
+// Throws: None.
+//--
+void
+CMICmnLLDBDebuggerHandleEvents::InitializeSignals()
+{
+ if (!m_bSignalsInitialized)
+ {
+ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess();
+ if (sbProcess.IsValid())
+ {
+ lldb::SBUnixSignals unix_signals = sbProcess.GetUnixSignals();
+ m_SIGINT = unix_signals.GetSignalNumberFromName("SIGINT");
+ m_SIGSTOP = unix_signals.GetSignalNumberFromName("SIGSTOP");
+ m_SIGSEGV = unix_signals.GetSignalNumberFromName("SIGSEGV");
+ m_SIGTRAP = unix_signals.GetSignalNumberFromName("SIGTRAP");
+ m_bSignalsInitialized = true;
+ }
+ }
+}
diff --git a/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h
index 65b397c13fd9..9b7b5d6f7b03 100644
--- a/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h
+++ b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h
@@ -7,22 +7,11 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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 "MICmnMIValueList.h"
#include "MICmnMIValueTuple.h"
#include "MIUtilSingletonBase.h"
@@ -50,7 +39,7 @@ class CMICmnLLDBDebuggerHandleEvents : public CMICmnBase, public MI::ISingleton<
bool Initialize(void);
bool Shutdown(void);
//
- bool HandleEvent(const lldb::SBEvent &vEvent, bool &vrbHandledEvent, bool &vrbExitAppEvent);
+ bool HandleEvent(const lldb::SBEvent &vEvent, bool &vrbHandledEvent);
// Methods:
private:
@@ -65,19 +54,25 @@ class CMICmnLLDBDebuggerHandleEvents : public CMICmnBase, public MI::ISingleton<
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 HandleEventSBProcess(const lldb::SBEvent &vEvent);
+ bool HandleEventSBTarget(const lldb::SBEvent &vEvent);
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 HandleProcessEventBroadcastBitStateChanged(const lldb::SBEvent &vEvent);
bool HandleProcessEventStateRunning(void);
bool HandleProcessEventStateExited(void);
- bool HandleProcessEventStateStopped(bool &vwrbShouldBrk);
+ bool HandleProcessEventStateStopped(const lldb::SBEvent &vrEvent, bool &vwrbShouldBrk);
bool HandleProcessEventStopReasonTrace(void);
bool HandleProcessEventStopReasonBreakpoint(void);
- bool HandleProcessEventStopSignal(bool &vwrbShouldBrk);
+ bool HandleProcessEventStopSignal(const lldb::SBEvent &vrEvent);
+ bool HandleProcessEventStopException(void);
bool HandleProcessEventStateSuspended(const lldb::SBEvent &vEvent);
+ bool HandleTargetEventBroadcastBitModulesLoaded(const lldb::SBEvent &vEvent);
+ bool HandleTargetEventBroadcastBitModulesUnloaded(const lldb::SBEvent &vEvent);
+ bool MiHelpGetModuleInfo(const lldb::SBModule &vModule, const bool vbWithExtraFields,
+ CMICmnMIOutOfBandRecord &vwrMiOutOfBandRecord);
bool MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &vwrMiValueTuple);
bool MiResultRecordToStdout(const CMICmnMIResultRecord &vrMiResultRecord);
bool MiOutOfBandRecordToStdout(const CMICmnMIOutOfBandRecord &vrMiResultRecord);
@@ -85,10 +80,15 @@ class CMICmnLLDBDebuggerHandleEvents : public CMICmnBase, public MI::ISingleton<
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);
+ void InitializeSignals();
+ bool m_bSignalsInitialized;
+ MIuint64 m_SIGINT;
+ MIuint64 m_SIGSTOP;
+ MIuint64 m_SIGSEGV;
+ MIuint64 m_SIGTRAP;
};
diff --git a/tools/lldb-mi/MICmnLLDBProxySBValue.cpp b/tools/lldb-mi/MICmnLLDBProxySBValue.cpp
index 6a07f207840e..b60ce1aa4c4f 100644
--- a/tools/lldb-mi/MICmnLLDBProxySBValue.cpp
+++ b/tools/lldb-mi/MICmnLLDBProxySBValue.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -115,11 +103,11 @@ bool
CMICmnLLDBProxySBValue::GetCString(const lldb::SBValue &vrValue, CMIUtilString &vwCString)
{
lldb::SBValue &rValue = const_cast<lldb::SBValue &>(vrValue);
- const MIchar *pCType = rValue.GetTypeName();
+ const char *pCType = rValue.GetTypeName();
if (pCType == nullptr)
return MIstatus::failure;
- const MIchar *pType = "unsigned char *";
+ const char *pType = "unsigned char *";
if (!CMIUtilString::Compare(pCType, pType))
return MIstatus::failure;
@@ -132,7 +120,7 @@ CMICmnLLDBProxySBValue::GetCString(const lldb::SBValue &vrValue, CMIUtilString &
lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
MIuint nBufferSize = 64;
bool bNeedResize = false;
- MIchar *pBuffer = static_cast<MIchar *>(::malloc(nBufferSize));
+ char *pBuffer = static_cast<char *>(::malloc(nBufferSize));
do
{
lldb::SBError error;
@@ -141,7 +129,7 @@ CMICmnLLDBProxySBValue::GetCString(const lldb::SBValue &vrValue, CMIUtilString &
{
bNeedResize = true;
nBufferSize = nBufferSize << 1;
- pBuffer = static_cast<MIchar *>(::realloc(pBuffer, nBufferSize));
+ pBuffer = static_cast<char *>(::realloc(pBuffer, nBufferSize));
}
else
bNeedResize = false;
diff --git a/tools/lldb-mi/MICmnLLDBProxySBValue.h b/tools/lldb-mi/MICmnLLDBProxySBValue.h
index 39befe9566f3..a4ff0b72b236 100644
--- a/tools/lldb-mi/MICmnLLDBProxySBValue.h
+++ b/tools/lldb-mi/MICmnLLDBProxySBValue.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmnLLDBUtilSBValue.cpp b/tools/lldb-mi/MICmnLLDBUtilSBValue.cpp
index 66a4efd5a96e..7ccb35e45449 100644
--- a/tools/lldb-mi/MICmnLLDBUtilSBValue.cpp
+++ b/tools/lldb-mi/MICmnLLDBUtilSBValue.cpp
@@ -7,22 +7,15 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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.
-//--
+// Third party headers:
+#include <cinttypes>
// In-house headers:
#include "MICmnLLDBUtilSBValue.h"
-#include "MIUtilString.h"
#include "MICmnLLDBDebugSessionInfo.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnMIValueTuple.h"
+#include "MIUtilString.h"
//++ ------------------------------------------------------------------------------------
// Details: CMICmnLLDBUtilSBValue constructor.
@@ -33,10 +26,13 @@
// Return: None.
// Throws: None.
//--
-CMICmnLLDBUtilSBValue::CMICmnLLDBUtilSBValue(const lldb::SBValue &vrValue, const bool vbHandleCharType /* = false */)
+CMICmnLLDBUtilSBValue::CMICmnLLDBUtilSBValue(const lldb::SBValue &vrValue, const bool vbHandleCharType /* = false */,
+ const bool vbHandleArrayType /* = true */)
: m_rValue(const_cast<lldb::SBValue &>(vrValue))
, m_pUnkwn("??")
+ , m_pComposite("{...}")
, m_bHandleCharType(vbHandleCharType)
+ , m_bHandleArrayType(vbHandleArrayType)
{
m_bValidSBValue = m_rValue.IsValid();
}
@@ -63,7 +59,7 @@ CMICmnLLDBUtilSBValue::~CMICmnLLDBUtilSBValue(void)
CMIUtilString
CMICmnLLDBUtilSBValue::GetName(void) const
{
- const MIchar *pName = m_bValidSBValue ? m_rValue.GetName() : nullptr;
+ const char *pName = m_bValidSBValue ? m_rValue.GetName() : nullptr;
const CMIUtilString text((pName != nullptr) ? pName : m_pUnkwn);
return text;
@@ -79,47 +75,286 @@ CMICmnLLDBUtilSBValue::GetName(void) const
// Throws: None.
//--
CMIUtilString
-CMICmnLLDBUtilSBValue::GetValue(void) const
+CMICmnLLDBUtilSBValue::GetValue(const bool vbExpandAggregates /* = false */) const
{
- CMIUtilString text;
+ if (!m_bValidSBValue)
+ return m_pUnkwn;
- if (m_bHandleCharType && IsCharType())
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ bool bPrintExpandAggregates = false;
+ bPrintExpandAggregates = rSessionInfo.SharedDataRetrieve<bool>(rSessionInfo.m_constStrPrintExpandAggregates,
+ bPrintExpandAggregates) && bPrintExpandAggregates;
+
+ const bool bHandleArrayTypeAsSimple = m_bHandleArrayType && !vbExpandAggregates && !bPrintExpandAggregates;
+ CMIUtilString value;
+ const bool bIsSimpleValue = GetSimpleValue(bHandleArrayTypeAsSimple, value);
+ if (bIsSimpleValue)
+ return value;
+
+ if (!vbExpandAggregates && !bPrintExpandAggregates)
+ return m_pComposite;
+
+ bool bPrintAggregateFieldNames = false;
+ bPrintAggregateFieldNames = !rSessionInfo.SharedDataRetrieve<bool>(rSessionInfo.m_constStrPrintAggregateFieldNames,
+ bPrintAggregateFieldNames) || bPrintAggregateFieldNames;
+
+ CMICmnMIValueTuple miValueTuple;
+ const bool bOk = GetCompositeValue(bPrintAggregateFieldNames, miValueTuple);
+ if (!bOk)
+ return m_pUnkwn;
+
+ value = miValueTuple.GetString();
+ return value;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve from the LLDB SB Value object the value of the variable described in
+// text if it has a simple format (not composite).
+// Type: Method.
+// Args: vwrValue - (W) The SBValue in a string format.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmnLLDBUtilSBValue::GetSimpleValue(const bool vbHandleArrayType, CMIUtilString &vwrValue) const
+{
+ const MIuint nChildren = m_rValue.GetNumChildren();
+ if (nChildren == 0)
{
- 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());
+ if (m_bHandleCharType && IsCharType())
+ {
+ vwrValue = GetSimpleValueChar();
+ return MIstatus::success;
+ }
+ else
+ {
+ const char *pValue = m_rValue.GetValue();
+ vwrValue = pValue != nullptr ? pValue : m_pUnkwn;
+ return MIstatus::success;
+ }
}
- else
+ else if (IsPointerType())
{
- const MIchar *pValue = m_bValidSBValue ? m_rValue.GetValue() : nullptr;
- text = (pValue != nullptr) ? pValue : m_pUnkwn;
+ if (m_bHandleCharType && IsFirstChildCharType())
+ {
+ vwrValue = GetSimpleValueCStringPointer();
+ return MIstatus::success;
+ }
+ else
+ {
+ const char *pValue = m_rValue.GetValue();
+ vwrValue = pValue != nullptr ? pValue : m_pUnkwn;
+ return MIstatus::success;
+ }
+ }
+ else if (IsArrayType())
+ {
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ bool bPrintCharArrayAsString = false;
+ bPrintCharArrayAsString = rSessionInfo.SharedDataRetrieve<bool>(rSessionInfo.m_constStrPrintCharArrayAsString,
+ bPrintCharArrayAsString) && bPrintCharArrayAsString;
+ if (bPrintCharArrayAsString && m_bHandleCharType && IsFirstChildCharType())
+ {
+ vwrValue = GetSimpleValueCStringArray();
+ return MIstatus::success;
+ }
+ else if (vbHandleArrayType)
+ {
+ vwrValue = CMIUtilString::Format("[%u]", nChildren);
+ return MIstatus::success;
+ }
}
- return text;
+ // Composite variable type i.e. struct
+ return MIstatus::failure;
}
//++ ------------------------------------------------------------------------------------
-// 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.
+// Details: Retrieve from the LLDB SB Value object the char value of the variable.
// Type: Method.
// Args: None.
-// Return: CMIUtilString - Text description of the variable's value.
+// Return: CMIUtilString - The char value of the variable.
// Throws: None.
//--
CMIUtilString
-CMICmnLLDBUtilSBValue::GetValueCString(void) const
+CMICmnLLDBUtilSBValue::GetSimpleValueChar(void) const
{
- CMIUtilString text;
+ const uint64_t value = m_rValue.GetValueAsUnsigned();
+ if (value == 0)
+ {
+ const uint64_t nFailValue = 1;
+ if (nFailValue == m_rValue.GetValueAsUnsigned(nFailValue))
+ return m_pUnkwn;
+ }
- if (m_bHandleCharType && IsCharType())
+ const lldb::BasicType eType = m_rValue.GetType().GetBasicType();
+ switch (eType)
{
- text = ReadCStringFromHostMemory(m_rValue);
+ default:
+ assert(0 && "value must be a char type");
+ case lldb::eBasicTypeChar:
+ case lldb::eBasicTypeSignedChar:
+ case lldb::eBasicTypeUnsignedChar:
+ {
+ const CMIUtilString prefix(CMIUtilString::ConvertToPrintableASCII((char)value));
+ return CMIUtilString::Format("%" PRIu8 " '%s'", (uint8_t)value, prefix.c_str());
+ }
+ case lldb::eBasicTypeChar16:
+ {
+ const CMIUtilString prefix(CMIUtilString::ConvertToPrintableASCII((char16_t)value));
+ return CMIUtilString::Format("U+%04" PRIx16 " u'%s'", (uint16_t)value, prefix.c_str());
+ }
+ case lldb::eBasicTypeChar32:
+ {
+ const CMIUtilString prefix(CMIUtilString::ConvertToPrintableASCII((char32_t)value));
+ return CMIUtilString::Format("U+%08" PRIx32 " U'%s'", (uint32_t)value, prefix.c_str());
+ }
}
+}
- return text;
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve from the LLDB SB Value object of type char* the c-string value.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - The c-string value of the variable.
+// Throws: None.
+//--
+CMIUtilString
+CMICmnLLDBUtilSBValue::GetSimpleValueCStringPointer(void) const
+{
+ const char *value = m_rValue.GetValue();
+ if (value == nullptr)
+ return m_pUnkwn;
+
+ lldb::SBValue child = m_rValue.GetChildAtIndex(0);
+ const lldb::BasicType eType = child.GetType().GetBasicType();
+ switch (eType)
+ {
+ default:
+ assert(0 && "child must be a char type");
+ case lldb::eBasicTypeChar:
+ case lldb::eBasicTypeSignedChar:
+ case lldb::eBasicTypeUnsignedChar:
+ {
+ // FIXME Add slashes before double quotes
+ const CMIUtilString prefix(ReadCStringFromHostMemory<char>(child).AddSlashes());
+ // 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
+ return CMIUtilString::Format("%s \"%s\"", value, prefix.c_str());
+ }
+ case lldb::eBasicTypeChar16:
+ {
+ // FIXME Add slashes before double quotes
+ const CMIUtilString prefix(ReadCStringFromHostMemory<char16_t>(child).AddSlashes());
+ return CMIUtilString::Format("%s u\"%s\"", value, prefix.c_str());
+ }
+ case lldb::eBasicTypeChar32:
+ {
+ // FIXME Add slashes before double quotes
+ const CMIUtilString prefix(ReadCStringFromHostMemory<char32_t>(child).AddSlashes());
+ return CMIUtilString::Format("%s U\"%s\"", value, prefix.c_str());
+ }
+ }
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve from the LLDB SB Value object of type char[] the c-string value.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - The c-string value of the variable.
+// Throws: None.
+//--
+CMIUtilString
+CMICmnLLDBUtilSBValue::GetSimpleValueCStringArray(void) const
+{
+ const MIuint nChildren = m_rValue.GetNumChildren();
+ lldb::SBValue child = m_rValue.GetChildAtIndex(0);
+ const lldb::BasicType eType = child.GetType().GetBasicType();
+ switch (eType)
+ {
+ default:
+ assert(0 && "value must be a char[] type");
+ case lldb::eBasicTypeChar:
+ case lldb::eBasicTypeSignedChar:
+ case lldb::eBasicTypeUnsignedChar:
+ {
+ // FIXME Add slashes before double quotes
+ const CMIUtilString prefix(ReadCStringFromHostMemory<char>(m_rValue, nChildren).AddSlashes());
+ // TODO: to match char* it should be the following
+ // return CMIUtilString::Format("[%u] \"%s\"", nChildren, prefix.c_str());
+ return CMIUtilString::Format("\"%s\"", prefix.c_str());
+ }
+ case lldb::eBasicTypeChar16:
+ {
+ // FIXME Add slashes before double quotes
+ const CMIUtilString prefix(ReadCStringFromHostMemory<char16_t>(m_rValue, nChildren).AddSlashes());
+ return CMIUtilString::Format("u\"%s\"", prefix.c_str());
+ }
+ case lldb::eBasicTypeChar32:
+ {
+ // FIXME Add slashes before double quotes
+ const CMIUtilString prefix(ReadCStringFromHostMemory<char32_t>(m_rValue, nChildren).AddSlashes());
+ return CMIUtilString::Format("U\"%s\"", prefix.c_str());
+ }
+ }
+}
+
+bool
+CMICmnLLDBUtilSBValue::GetCompositeValue(const bool vbPrintFieldNames, CMICmnMIValueTuple &vwrMiValueTuple,
+ const MIuint vnDepth /* = 1 */) const
+{
+ const MIuint nMaxDepth = 10;
+ const MIuint nChildren = m_rValue.GetNumChildren();
+ for (MIuint i = 0; i < nChildren; ++i)
+ {
+ const lldb::SBValue member = m_rValue.GetChildAtIndex(i);
+ const CMICmnLLDBUtilSBValue utilMember(member, m_bHandleCharType, m_bHandleArrayType);
+ const bool bHandleArrayTypeAsSimple = false;
+ CMIUtilString value;
+ const bool bIsSimpleValue = utilMember.GetSimpleValue(bHandleArrayTypeAsSimple, value);
+ if (bIsSimpleValue)
+ {
+ // OK. Value is simple (not composite) and was successfully got
+ }
+ else if (vnDepth < nMaxDepth)
+ {
+ // Need to get value from composite type
+ CMICmnMIValueTuple miValueTuple;
+ const bool bOk = utilMember.GetCompositeValue(vbPrintFieldNames, miValueTuple, vnDepth + 1);
+ if (!bOk)
+ // Can't obtain composite type
+ value = m_pUnkwn;
+ else
+ // OK. Value is composite and was successfully got
+ value = miValueTuple.GetString();
+ }
+ else
+ {
+ // Need to get value from composite type, but vnMaxDepth is reached
+ value = m_pComposite;
+ }
+ const bool bNoQuotes = true;
+ const CMICmnMIValueConst miValueConst(value, bNoQuotes);
+ if (vbPrintFieldNames)
+ {
+ const bool bUseSpacing = true;
+ const CMICmnMIValueResult miValueResult(utilMember.GetName(), miValueConst, bUseSpacing);
+ const bool bOk = vwrMiValueTuple.Add(miValueResult, bUseSpacing);
+ if (!bOk)
+ return MIstatus::failure;
+ }
+ else
+ {
+ const bool bUseSpacing = false;
+ const bool bOk = vwrMiValueTuple.Add(miValueConst, bUseSpacing);
+ if (!bOk)
+ return MIstatus::failure;
+ }
+ }
+
+ return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
@@ -133,15 +368,23 @@ CMICmnLLDBUtilSBValue::GetValueCString(void) const
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));
+ switch (eType)
+ {
+ case lldb::eBasicTypeChar:
+ case lldb::eBasicTypeSignedChar:
+ case lldb::eBasicTypeUnsignedChar:
+ case lldb::eBasicTypeChar16:
+ case lldb::eBasicTypeChar32:
+ return true;
+ default:
+ return false;
+ }
}
//++ ------------------------------------------------------------------------------------
-// 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
+// Details: Retrieve the flag stating whether first 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.
@@ -149,7 +392,7 @@ CMICmnLLDBUtilSBValue::IsCharType(void) const
// Throws: None.
//--
bool
-CMICmnLLDBUtilSBValue::IsChildCharType(void) const
+CMICmnLLDBUtilSBValue::IsFirstChildCharType(void) const
{
const MIuint nChildren = m_rValue.GetNumChildren();
@@ -157,74 +400,87 @@ CMICmnLLDBUtilSBValue::IsChildCharType(void) const
if (nChildren == 0)
return false;
- // Is it a composite type
- if (nChildren > 1)
- return false;
-
- lldb::SBValue member = m_rValue.GetChildAtIndex(0);
+ const 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.
+// Details: Retrieve the flag stating whether this value object is a integer type or some
+// other type. Char type can be signed or unsigned and short or long/very long.
// Type: Method.
// Args: None.
-// Return: CMIUtilString - Text description of the variable's value.
+// Return: bool - True = Yes is a integer type, false = some other type.
// Throws: None.
//--
-CMIUtilString
-CMICmnLLDBUtilSBValue::GetChildValueCString(void) const
+bool
+CMICmnLLDBUtilSBValue::IsIntegerType(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;
+ const lldb::BasicType eType = m_rValue.GetType().GetBasicType();
+ return ((eType == lldb::eBasicTypeShort) || (eType == lldb::eBasicTypeUnsignedShort) ||
+ (eType == lldb::eBasicTypeInt) || (eType == lldb::eBasicTypeUnsignedInt) ||
+ (eType == lldb::eBasicTypeLong) || (eType == lldb::eBasicTypeUnsignedLong) ||
+ (eType == lldb::eBasicTypeLongLong) || (eType == lldb::eBasicTypeUnsignedLongLong) ||
+ (eType == lldb::eBasicTypeInt128) || (eType == lldb::eBasicTypeUnsignedInt128));
+}
- lldb::SBValue member = m_rValue.GetChildAtIndex(0);
- const CMICmnLLDBUtilSBValue utilValue(member);
- if (m_bHandleCharType && utilValue.IsCharType())
- {
- text = ReadCStringFromHostMemory(member);
- }
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the flag stating whether this value object is a pointer type or some
+// other type.
+// Type: Method.
+// Args: None.
+// Return: bool - True = Yes is a pointer type, false = some other type.
+// Throws: None.
+//--
+bool
+CMICmnLLDBUtilSBValue::IsPointerType(void) const
+{
+ return m_rValue.GetType().IsPointerType();
+}
- return text;
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the flag stating whether this value object is an array type or some
+// other type.
+// Type: Method.
+// Args: None.
+// Return: bool - True = Yes is an array type, false = some other type.
+// Throws: None.
+//--
+bool
+CMICmnLLDBUtilSBValue::IsArrayType(void) const
+{
+ return m_rValue.GetType().IsArrayType();
}
//++ ------------------------------------------------------------------------------------
// 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.
+// Args: vrValue - (R) LLDB SBValue variable object.
// Return: CMIUtilString - Text description of the variable's value.
// Throws: None.
//--
+template <typename charT>
CMIUtilString
-CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory(const lldb::SBValue &vrValueObj) const
+CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory(lldb::SBValue &vrValue, const MIuint vnMaxLen) 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];
+ std::string result;
+ lldb::addr_t addr = vrValue.GetLoadAddress(), end_addr = addr + vnMaxLen * sizeof(charT);
+ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetProcess();
lldb::SBError error;
- const MIuint64 nReadBytes = rSessionInfo.GetProcess().ReadMemory(addr, (void *)pBufferMemory, nBytes, error);
- MIunused(nReadBytes);
- text = CMIUtilString::Format("\\\"%s\\\"", pBufferMemory);
- delete[] pBufferMemory;
+ while (addr < end_addr)
+ {
+ charT ch;
+ const MIuint64 nReadBytes = process.ReadMemory(addr, &ch, sizeof(ch), error);
+ if (error.Fail() || nReadBytes != sizeof(ch))
+ return m_pUnkwn;
+ else if (ch == 0)
+ break;
+ result.append(CMIUtilString::ConvertToPrintableASCII(ch));
+ addr += sizeof(ch);
+ }
- return text;
+ return result.c_str();
}
//++ ------------------------------------------------------------------------------------
@@ -265,7 +521,7 @@ CMICmnLLDBUtilSBValue::IsValueUnknown(void) const
CMIUtilString
CMICmnLLDBUtilSBValue::GetTypeName(void) const
{
- const MIchar *pName = m_bValidSBValue ? m_rValue.GetTypeName() : nullptr;
+ const char *pName = m_bValidSBValue ? m_rValue.GetTypeName() : nullptr;
const CMIUtilString text((pName != nullptr) ? pName : m_pUnkwn);
return text;
@@ -281,7 +537,7 @@ CMICmnLLDBUtilSBValue::GetTypeName(void) const
CMIUtilString
CMICmnLLDBUtilSBValue::GetTypeNameDisplay(void) const
{
- const MIchar *pName = m_bValidSBValue ? m_rValue.GetDisplayTypeName() : nullptr;
+ const char *pName = m_bValidSBValue ? m_rValue.GetDisplayTypeName() : nullptr;
const CMIUtilString text((pName != nullptr) ? pName : m_pUnkwn);
return text;
@@ -313,7 +569,7 @@ CMICmnLLDBUtilSBValue::HasName(void) const
{
bool bHasAName = false;
- const MIchar *pName = m_bValidSBValue ? m_rValue.GetDisplayTypeName() : nullptr;
+ const char *pName = m_bValidSBValue ? m_rValue.GetDisplayTypeName() : nullptr;
if (pName != nullptr)
{
bHasAName = (CMIUtilString(pName).length() > 0);
diff --git a/tools/lldb-mi/MICmnLLDBUtilSBValue.h b/tools/lldb-mi/MICmnLLDBUtilSBValue.h
index a3f2c9c0ffc9..468170b6a731 100644
--- a/tools/lldb-mi/MICmnLLDBUtilSBValue.h
+++ b/tools/lldb-mi/MICmnLLDBUtilSBValue.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -26,6 +14,7 @@
// In-house headers:
#include "MIDataTypes.h"
+#include "MICmnMIValueTuple.h"
// Declerations:
class CMIUtilString;
@@ -41,17 +30,19 @@ class CMICmnLLDBUtilSBValue
{
// Methods:
public:
- /* ctor */ CMICmnLLDBUtilSBValue(const lldb::SBValue &vrValue, const bool vbHandleCharType = false);
+ /* ctor */ CMICmnLLDBUtilSBValue(const lldb::SBValue &vrValue, const bool vbHandleCharType = false,
+ const bool vbHandleArrayType = true);
/* dtor */ ~CMICmnLLDBUtilSBValue(void);
//
CMIUtilString GetName(void) const;
- CMIUtilString GetValue(void) const;
- CMIUtilString GetValueCString(void) const;
- CMIUtilString GetChildValueCString(void) const;
+ CMIUtilString GetValue(const bool vbExpandAggregates = false) const;
CMIUtilString GetTypeName(void) const;
CMIUtilString GetTypeNameDisplay(void) const;
bool IsCharType(void) const;
- bool IsChildCharType(void) const;
+ bool IsFirstChildCharType(void) const;
+ bool IsIntegerType(void) const;
+ bool IsPointerType(void) const;
+ bool IsArrayType(void) const;
bool IsLLDBVariable(void) const;
bool IsNameUnknown(void) const;
bool IsValueUnknown(void) const;
@@ -60,12 +51,19 @@ class CMICmnLLDBUtilSBValue
// Methods:
private:
- CMIUtilString ReadCStringFromHostMemory(const lldb::SBValue &vrValueObj) const;
+ template <typename charT> CMIUtilString ReadCStringFromHostMemory(lldb::SBValue &vrValue, const MIuint vnMaxLen = UINT32_MAX) const;
+ bool GetSimpleValue(const bool vbHandleArrayType, CMIUtilString &vrValue) const;
+ CMIUtilString GetSimpleValueChar(void) const;
+ CMIUtilString GetSimpleValueCStringPointer(void) const;
+ CMIUtilString GetSimpleValueCStringArray(void) const;
+ bool GetCompositeValue(const bool vbPrintFieldNames, CMICmnMIValueTuple &vwrMiValueTuple, const MIuint vnDepth = 1) 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.
+ const char *m_pUnkwn;
+ const char *m_pComposite;
+ 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.
+ bool m_bHandleArrayType; // True = Yes return special stub for array type, false = just return data.
};
diff --git a/tools/lldb-mi/MICmnLog.cpp b/tools/lldb-mi/MICmnLog.cpp
index dc7a93d29776..a88ba6b5782a 100644
--- a/tools/lldb-mi/MICmnLog.cpp
+++ b/tools/lldb-mi/MICmnLog.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmnLog.h b/tools/lldb-mi/MICmnLog.h
index 6884b614896d..30505359d749 100644
--- a/tools/lldb-mi/MICmnLog.h
+++ b/tools/lldb-mi/MICmnLog.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmnLogMediumFile.cpp b/tools/lldb-mi/MICmnLogMediumFile.cpp
index add4426b9352..4080bc5cf29d 100644
--- a/tools/lldb-mi/MICmnLogMediumFile.cpp
+++ b/tools/lldb-mi/MICmnLogMediumFile.cpp
@@ -7,24 +7,12 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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__)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__linux__)
#include "MIUtilSystemLinux.h"
#elif defined(__APPLE__)
#include "MIUtilSystemOsx.h"
@@ -39,7 +27,9 @@
//--
CMICmnLogMediumFile::CMICmnLogMediumFile(void)
: m_constThisMediumName(MIRSRC(IDS_MEDIUMFILE_NAME))
- , m_constMediumFileName("lldb-mi-log.txt")
+ , m_constMediumFileNameFormat("lldb-mi-%s.log")
+ , m_strMediumFileName(MIRSRC(IDS_MEDIUMFILE_ERR_INVALID_PATH))
+ , m_strMediumFileDirectory(MIRSRC(IDS_MEDIUMFILE_ERR_INVALID_PATH))
, m_fileNamePath(MIRSRC(IDS_MEDIUMFILE_ERR_INVALID_PATH))
, m_eVerbosityType(CMICmnLog::eLogVerbosity_Log)
, m_strDate(CMIUtilDateTimeStd().GetDate())
@@ -84,7 +74,8 @@ CMICmnLogMediumFile::Instance(void)
bool
CMICmnLogMediumFile::Initialize(void)
{
- m_bInitialized = FileFormFileNamePath();
+ m_bInitialized = CMIUtilSystem().GetLogFilesPath(m_strMediumFileDirectory);
+ m_bInitialized &= FileFormFileNamePath();
return m_bInitialized;
}
@@ -225,21 +216,15 @@ CMICmnLogMediumFile::FileFormFileNamePath(void)
m_fileNamePath = MIRSRC(IDS_MEDIUMFILE_ERR_INVALID_PATH);
- CMIUtilString strPathName;
- if (CMIUtilSystem().GetLogFilesPath(strPathName))
+ if (m_strMediumFileDirectory.compare(MIRSRC(IDS_MEDIUMFILE_ERR_INVALID_PATH)) != 0)
{
- 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.
+ CMIUtilDateTimeStd date;
+ m_strMediumFileName = CMIUtilString::Format(m_constMediumFileNameFormat.c_str(), date.GetDateTimeLogFilename().c_str());
+
#if defined(_MSC_VER)
- m_fileNamePath = CMIUtilString::Format("%s\\%s", strPath.c_str(), m_constMediumFileName.c_str());
+ m_fileNamePath = CMIUtilString::Format("%s\\%s", m_strMediumFileDirectory.c_str(), m_strMediumFileName.c_str());
#else
- m_fileNamePath = CMIUtilString::Format("%s", m_constMediumFileName.c_str());
+ m_fileNamePath = CMIUtilString::Format("%s/%s", m_strMediumFileDirectory.c_str(), m_strMediumFileName.c_str());
#endif // defined ( _MSC_VER )
return MIstatus::success;
@@ -273,7 +258,7 @@ CMICmnLogMediumFile::GetFileNamePath(void) const
const CMIUtilString &
CMICmnLogMediumFile::GetFileName(void) const
{
- return m_constMediumFileName;
+ return m_strMediumFileName;
}
//++ ------------------------------------------------------------------------------------
@@ -291,15 +276,15 @@ CMICmnLogMediumFile::MassagedData(const CMIUtilString &vData, const CMICmnLog::E
{
const CMIUtilString strCr("\n");
CMIUtilString data;
- const MIchar verbosityCode(ConvertLogVerbosityTypeToId(veType));
+ const char 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())
+ const size_t pos = vData.rfind(strCr);
+ if (pos == vData.size())
return data;
// ... did not have an EOL so add one
@@ -315,10 +300,10 @@ CMICmnLogMediumFile::MassagedData(const CMIUtilString &vData, const CMICmnLog::E
// Return: wchar_t - A letter.
// Throws: None.
//--
-MIchar
+char
CMICmnLogMediumFile::ConvertLogVerbosityTypeToId(const CMICmnLog::ELogVerbosity veType) const
{
- MIchar c = 0;
+ char c = 0;
if (veType != 0)
{
MIuint cnt = 0;
@@ -397,11 +382,11 @@ CMICmnLogMediumFile::ConvertCr(const CMIUtilString &vData) const
if (strCr == rCrCmpat)
return vData;
- const MIuint nSizeCmpat(rCrCmpat.size());
- const MIuint nSize(strCr.size());
+ const size_t nSizeCmpat(rCrCmpat.size());
+ const size_t nSize(strCr.size());
CMIUtilString strConv(vData);
- MIint pos = strConv.find(strCr);
- while (pos != (MIint)CMIUtilString::npos)
+ size_t pos = strConv.find(strCr);
+ while (pos != CMIUtilString::npos)
{
strConv.replace(pos, nSize, rCrCmpat);
pos = strConv.find(strCr, pos + nSizeCmpat);
@@ -438,3 +423,19 @@ CMICmnLogMediumFile::GetLineReturn(void) const
{
return m_file.GetLineReturn();
}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the diretory to place the log file.
+// Type: Method.
+// Args: vPath - (R) Path to log.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool
+CMICmnLogMediumFile::SetDirectory(const CMIUtilString &vPath)
+{
+ m_strMediumFileDirectory = vPath;
+
+ return FileFormFileNamePath();
+}
diff --git a/tools/lldb-mi/MICmnLogMediumFile.h b/tools/lldb-mi/MICmnLogMediumFile.h
index 8496320db678..53961d8f4f73 100644
--- a/tools/lldb-mi/MICmnLogMediumFile.h
+++ b/tools/lldb-mi/MICmnLogMediumFile.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -55,6 +43,7 @@ class CMICmnLogMediumFile : public CMICmnBase, public CMICmnLog::IMedium
bool IsOk(void) const;
bool IsFileExist(void) const;
const CMIUtilString &GetLineReturn(void) const;
+ bool SetDirectory(const CMIUtilString &vPath);
// Overridden:
public:
@@ -77,14 +66,16 @@ class CMICmnLogMediumFile : public CMICmnBase, public CMICmnLog::IMedium
bool FileFormFileNamePath(void);
CMIUtilString MassagedData(const CMIUtilString &vData, const CMICmnLog::ELogVerbosity veType);
bool FileWriteHeader(void);
- MIchar ConvertLogVerbosityTypeToId(const CMICmnLog::ELogVerbosity veType) const;
+ char ConvertLogVerbosityTypeToId(const CMICmnLog::ELogVerbosity veType) const;
CMIUtilString ConvertCr(const CMIUtilString &vData) const;
// Attributes:
private:
const CMIUtilString m_constThisMediumName;
- const CMIUtilString m_constMediumFileName;
+ const CMIUtilString m_constMediumFileNameFormat;
//
+ CMIUtilString m_strMediumFileName;
+ CMIUtilString m_strMediumFileDirectory;
CMIUtilString m_fileNamePath;
MIuint m_eVerbosityType;
CMIUtilString m_strDate;
diff --git a/tools/lldb-mi/MICmnMIOutOfBandRecord.cpp b/tools/lldb-mi/MICmnMIOutOfBandRecord.cpp
index 2977753038a6..84c6695de354 100644
--- a/tools/lldb-mi/MICmnMIOutOfBandRecord.cpp
+++ b/tools/lldb-mi/MICmnMIOutOfBandRecord.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -36,7 +24,10 @@ CMICmnMIOutOfBandRecord::MapOutOfBandToOutOfBandText_t ms_MapOutOfBandToOutOfBan
{CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, "thread-group-started"},
{CMICmnMIOutOfBandRecord::eOutOfBand_ThreadCreated, "thread-created"},
{CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, "thread-exited"},
- {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, "thread-selected"}};
+ {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, "thread-selected"},
+ {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleLoaded, "library-loaded"},
+ {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleUnloaded, "library-unloaded"},
+ {CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, ""}};
CMICmnMIOutOfBandRecord::MapOutOfBandToOutOfBandText_t ms_constMapAsyncRecordTextToToken = {
{CMICmnMIOutOfBandRecord::eOutOfBand_Running, "*"},
{CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, "*"},
@@ -49,7 +40,10 @@ CMICmnMIOutOfBandRecord::MapOutOfBandToOutOfBandText_t ms_constMapAsyncRecordTex
{CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, "="},
{CMICmnMIOutOfBandRecord::eOutOfBand_ThreadCreated, "="},
{CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, "="},
- {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, "="}};
+ {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, "="},
+ {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleLoaded, "="},
+ {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleUnloaded, "="},
+ {CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, "@"}};
//++ ------------------------------------------------------------------------------------
// Details: CMICmnMIOutOfBandRecord constructor.
@@ -81,14 +75,30 @@ CMICmnMIOutOfBandRecord::CMICmnMIOutOfBandRecord(const OutOfBand_e veType)
// Details: CMICmnMIOutOfBandRecord constructor.
// Type: Method.
// Args: veType - (R) A MI Out-of-Bound enumeration.
-// vMIResult - (R) A MI result object.
+// vConst - (R) A MI const object.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIOutOfBandRecord::CMICmnMIOutOfBandRecord(const OutOfBand_e veType, const CMICmnMIValueConst &vConst)
+ : m_eResultAsyncRecordClass(veType)
+ , m_strAsyncRecord(MIRSRC(IDS_CMD_ERR_EVENT_HANDLED_BUT_NO_ACTION))
+{
+ BuildAsyncRecord();
+ m_strAsyncRecord += vConst.GetString();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIOutOfBandRecord constructor.
+// Type: Method.
+// Args: veType - (R) A MI Out-of-Bound enumeration.
+// vResult - (R) A MI result object.
// Return: None.
// Throws: None.
//--
-CMICmnMIOutOfBandRecord::CMICmnMIOutOfBandRecord(const OutOfBand_e veType, const CMICmnMIValueResult &vValue)
+CMICmnMIOutOfBandRecord::CMICmnMIOutOfBandRecord(const OutOfBand_e veType, const CMICmnMIValueResult &vResult)
: m_eResultAsyncRecordClass(veType)
, m_strAsyncRecord(MIRSRC(IDS_CMD_ERR_EVENT_HANDLED_BUT_NO_ACTION))
- , m_partResult(vValue)
+ , m_partResult(vResult)
{
BuildAsyncRecord();
Add(m_partResult);
@@ -133,7 +143,7 @@ CMICmnMIOutOfBandRecord::GetString(void) const
bool
CMICmnMIOutOfBandRecord::BuildAsyncRecord(void)
{
- const MIchar *pFormat = "%s%s";
+ const char *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());
@@ -144,16 +154,16 @@ CMICmnMIOutOfBandRecord::BuildAsyncRecord(void)
//++ ------------------------------------------------------------------------------------
// Details: Add to *this Out-of-band record additional information.
// Type: Method.
-// Args: vMIValue - (R) A MI value derived object.
+// Args: vResult - (R) A MI result object.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
-CMICmnMIOutOfBandRecord::Add(const CMICmnMIValue &vMIValue)
+CMICmnMIOutOfBandRecord::Add(const CMICmnMIValueResult &vResult)
{
m_strAsyncRecord += ",";
- m_strAsyncRecord += vMIValue.GetString();
+ m_strAsyncRecord += vResult.GetString();
return MIstatus::success;
}
diff --git a/tools/lldb-mi/MICmnMIOutOfBandRecord.h b/tools/lldb-mi/MICmnMIOutOfBandRecord.h
index 179e37523524..60a67165a3ff 100644
--- a/tools/lldb-mi/MICmnMIOutOfBandRecord.h
+++ b/tools/lldb-mi/MICmnMIOutOfBandRecord.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -27,6 +15,7 @@
// In-house headers:
#include "MICmnBase.h"
#include "MIUtilString.h"
+#include "MICmnMIValueConst.h"
#include "MICmnMIValueResult.h"
//++ ============================================================================
@@ -73,6 +62,9 @@ class CMICmnMIOutOfBandRecord : public CMICmnBase
eOutOfBand_ThreadCreated,
eOutOfBand_ThreadExited,
eOutOfBand_ThreadSelected,
+ eOutOfBand_TargetModuleLoaded,
+ eOutOfBand_TargetModuleUnloaded,
+ eOutOfBand_TargetStreamOutput,
eOutOfBand_count // Always the last one
};
@@ -85,10 +77,11 @@ class CMICmnMIOutOfBandRecord : public CMICmnBase
public:
/* ctor */ CMICmnMIOutOfBandRecord(void);
/* ctor */ CMICmnMIOutOfBandRecord(const OutOfBand_e veType);
- /* ctor */ CMICmnMIOutOfBandRecord(const OutOfBand_e veType, const CMICmnMIValueResult &vValue);
+ /* ctor */ CMICmnMIOutOfBandRecord(const OutOfBand_e veType, const CMICmnMIValueConst &vConst);
+ /* ctor */ CMICmnMIOutOfBandRecord(const OutOfBand_e veType, const CMICmnMIValueResult &vResult);
//
const CMIUtilString &GetString(void) const;
- bool Add(const CMICmnMIValue &vMIValue);
+ bool Add(const CMICmnMIValueResult &vResult);
// Overridden:
public:
diff --git a/tools/lldb-mi/MICmnMIResultRecord.cpp b/tools/lldb-mi/MICmnMIResultRecord.cpp
index 21cf326aca5e..49a31c87519f 100644
--- a/tools/lldb-mi/MICmnMIResultRecord.cpp
+++ b/tools/lldb-mi/MICmnMIResultRecord.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -118,7 +106,7 @@ CMICmnMIResultRecord::GetString(void) const
bool
CMICmnMIResultRecord::BuildResultRecord(void)
{
- const MIchar *pFormat = "%s%s%s";
+ const char *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());
diff --git a/tools/lldb-mi/MICmnMIResultRecord.h b/tools/lldb-mi/MICmnMIResultRecord.h
index 9d1f188c1eef..92666ab87733 100644
--- a/tools/lldb-mi/MICmnMIResultRecord.h
+++ b/tools/lldb-mi/MICmnMIResultRecord.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmnMIValue.cpp b/tools/lldb-mi/MICmnMIValue.cpp
index 8c0440115bf3..2f7041427d2b 100644
--- a/tools/lldb-mi/MICmnMIValue.cpp
+++ b/tools/lldb-mi/MICmnMIValue.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmnMIValue.h b/tools/lldb-mi/MICmnMIValue.h
index 2b60168db524..d5de4275231b 100644
--- a/tools/lldb-mi/MICmnMIValue.h
+++ b/tools/lldb-mi/MICmnMIValue.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmnMIValueConst.cpp b/tools/lldb-mi/MICmnMIValueConst.cpp
index 7aa0f7903558..dd4b99344293 100644
--- a/tools/lldb-mi/MICmnMIValueConst.cpp
+++ b/tools/lldb-mi/MICmnMIValueConst.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -85,13 +73,13 @@ CMICmnMIValueConst::BuildConst(void)
}
else
{
- const MIchar *pFormat = "%s%s%s";
+ const char *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";
+ const char *pFormat = "%s%s";
m_strValue = CMIUtilString::Format(pFormat, ms_constStrDblQuote.c_str(), ms_constStrDblQuote.c_str());
}
diff --git a/tools/lldb-mi/MICmnMIValueConst.h b/tools/lldb-mi/MICmnMIValueConst.h
index 72be01fa3db1..72b5f2455f42 100644
--- a/tools/lldb-mi/MICmnMIValueConst.h
+++ b/tools/lldb-mi/MICmnMIValueConst.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmnMIValueList.cpp b/tools/lldb-mi/MICmnMIValueList.cpp
index 2e6078cbea1f..68eceab09cd2 100644
--- a/tools/lldb-mi/MICmnMIValueList.cpp
+++ b/tools/lldb-mi/MICmnMIValueList.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -88,7 +76,7 @@ CMICmnMIValueList::~CMICmnMIValueList(void)
bool
CMICmnMIValueList::BuildList(void)
{
- const MIchar *pFormat = "[%s]";
+ const char *pFormat = "[%s]";
m_strValue = CMIUtilString::Format(pFormat, m_strValue.c_str());
return MIstatus::success;
@@ -148,7 +136,7 @@ CMICmnMIValueList::BuildList(const CMICmnMIValueResult &vResult)
}
const CMIUtilString data(ExtractContentNoBrackets());
- const MIchar *pFormat = "[%s,%s]";
+ const char *pFormat = "[%s,%s]";
m_strValue = CMIUtilString::Format(pFormat, data.c_str(), vResult.GetString().c_str());
return MIstatus::success;
@@ -175,9 +163,12 @@ CMICmnMIValueList::BuildList(const CMICmnMIValue &vValue)
return BuildList();
}
- const MIchar *pFormat = "[%s,%s]";
- m_strValue = m_strValue.FindAndReplace("[", "");
- m_strValue = m_strValue.FindAndReplace("]", "");
+ // Remove already present '[' and ']' from the start and end
+ m_strValue = m_strValue.Trim();
+ size_t len = m_strValue.size();
+ if ( (len > 1) && (m_strValue[0] == '[') && (m_strValue[len - 1] == ']') )
+ m_strValue = m_strValue.substr(1, len - 2);
+ const char *pFormat = "[%s,%s]";
m_strValue = CMIUtilString::Format(pFormat, m_strValue.c_str(), vValue.GetString().c_str());
return MIstatus::success;
diff --git a/tools/lldb-mi/MICmnMIValueList.h b/tools/lldb-mi/MICmnMIValueList.h
index e7811e7d7bab..85bc5d4fbc99 100644
--- a/tools/lldb-mi/MICmnMIValueList.h
+++ b/tools/lldb-mi/MICmnMIValueList.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmnMIValueResult.cpp b/tools/lldb-mi/MICmnMIValueResult.cpp
index 7735844b14de..55d93ce40ca7 100644
--- a/tools/lldb-mi/MICmnMIValueResult.cpp
+++ b/tools/lldb-mi/MICmnMIValueResult.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -60,7 +48,7 @@ CMICmnMIValueResult::CMICmnMIValueResult(const CMIUtilString &vrVariable, const
// 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.
+// vbUseSpacing - (R) True = put space separators into the string, false = no spaces used.
// Return: None.
// Throws: None.
//--
@@ -95,7 +83,7 @@ CMICmnMIValueResult::~CMICmnMIValueResult(void)
bool
CMICmnMIValueResult::BuildResult(void)
{
- const MIchar *pFormat = m_bUseSpacing ? "%s %s %s" : "%s%s%s";
+ const char *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;
@@ -113,7 +101,7 @@ CMICmnMIValueResult::BuildResult(void)
bool
CMICmnMIValueResult::BuildResult(const CMIUtilString &vVariable, const CMICmnMIValue &vValue)
{
- const MIchar *pFormat = m_bUseSpacing ? "%s, %s %s %s" : "%s,%s%s%s";
+ const char *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());
diff --git a/tools/lldb-mi/MICmnMIValueResult.h b/tools/lldb-mi/MICmnMIValueResult.h
index ec73e713bc93..99051bfc3f26 100644
--- a/tools/lldb-mi/MICmnMIValueResult.h
+++ b/tools/lldb-mi/MICmnMIValueResult.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -71,5 +59,5 @@ class CMICmnMIValueResult : public CMICmnMIValue
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
+ bool m_bUseSpacing; // True = put space separators into the string, false = no spaces used
};
diff --git a/tools/lldb-mi/MICmnMIValueTuple.cpp b/tools/lldb-mi/MICmnMIValueTuple.cpp
index 61fad88b5517..aa92b1f62280 100644
--- a/tools/lldb-mi/MICmnMIValueTuple.cpp
+++ b/tools/lldb-mi/MICmnMIValueTuple.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -54,7 +42,7 @@ CMICmnMIValueTuple::CMICmnMIValueTuple(const CMICmnMIValueResult &vResult)
// Details: CMICmnMIValueTuple constructor.
// Type: Method.
// Args: vResult - (R) MI result object.
-// vbUseSpacing - (R) True = put space seperators into the string, false = no spaces used.
+// vbUseSpacing - (R) True = put space separators into the string, false = no spaces used.
// Return: None.
// Throws: None.
//--
@@ -88,7 +76,7 @@ CMICmnMIValueTuple::~CMICmnMIValueTuple(void)
bool
CMICmnMIValueTuple::BuildTuple(void)
{
- const MIchar *pFormat = "{%s}";
+ const char *pFormat = "{%s}";
m_strValue = CMIUtilString::Format(pFormat, m_strValue.c_str());
return MIstatus::success;
@@ -122,7 +110,7 @@ CMICmnMIValueTuple::BuildTuple(const CMICmnMIValueResult &vResult)
m_strValue = m_strValue.substr(0, m_strValue.size() - 1);
}
- const MIchar *pFormat = m_bSpaceAfterComma ? "{%s, %s}" : "{%s,%s}";
+ const char *pFormat = m_bSpaceAfterComma ? "{%s, %s}" : "{%s,%s}";
m_strValue = CMIUtilString::Format(pFormat, m_strValue.c_str(), vResult.GetString().c_str());
return MIstatus::success;
@@ -148,7 +136,7 @@ CMICmnMIValueTuple::BuildTuple(const CMIUtilString &vValue)
}
const CMIUtilString data(ExtractContentNoBrackets());
- const MIchar *pFormat = m_bSpaceAfterComma ? "{%s, %s}" : "{%s,%s}";
+ const char *pFormat = m_bSpaceAfterComma ? "{%s, %s}" : "{%s,%s}";
m_strValue = CMIUtilString::Format(pFormat, data.c_str(), vValue.c_str());
return MIstatus::success;
@@ -176,7 +164,7 @@ CMICmnMIValueTuple::Add(const CMICmnMIValueResult &vResult)
// 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.
+// vbUseSpacing - (R) True = put space separators into the string, false = no spaces used.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
@@ -194,7 +182,7 @@ CMICmnMIValueTuple::Add(const CMICmnMIValueResult &vResult, const bool vbUseSpac
// 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.
+// vbUseSpacing - (R) True = put space separators into the string, false = no spaces used.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
diff --git a/tools/lldb-mi/MICmnMIValueTuple.h b/tools/lldb-mi/MICmnMIValueTuple.h
index d5cc5326ea44..3b6a8835d25f 100644
--- a/tools/lldb-mi/MICmnMIValueTuple.h
+++ b/tools/lldb-mi/MICmnMIValueTuple.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -72,5 +60,5 @@ class CMICmnMIValueTuple : public CMICmnMIValue
// Attributes:
private:
- bool m_bSpaceAfterComma; // True = put space seperators into the string, false = no spaces used
+ bool m_bSpaceAfterComma; // True = put space separators into the string, false = no spaces used
};
diff --git a/tools/lldb-mi/MICmnResources.cpp b/tools/lldb-mi/MICmnResources.cpp
index bc1fa3025cd6..3d8583f29d84 100644
--- a/tools/lldb-mi/MICmnResources.cpp
+++ b/tools/lldb-mi/MICmnResources.cpp
@@ -7,19 +7,8 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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 <inttypes.h> // For PRIx64
#include "assert.h"
// In-house headers:
@@ -62,9 +51,6 @@ const CMICmnResources::SRsrcTextData CMICmnResources::ms_pResourceId2TextData[]
{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."},
@@ -75,14 +61,13 @@ const CMICmnResources::SRsrcTextData CMICmnResources::ms_pResourceId2TextData[]
{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_INTERPRETER, "--interpreter\n\t This option is kept for backward compatibility. This executable always run in MI mode"},
+ {IDE_MI_APP_ARG_EXECUTEABLE, "--executable\n\tUse the MI Driver in MI mode for the debugging the specified executable." },
+ {IDE_MI_APP_ARG_SOURCE, "-s <filename>\n--source <filename>\n\t"
+ "Tells the debugger to read in and execute the lldb commands in the\n\t"
+ "given file, after any file provided on the command line has been\n\tloaded."},
{IDE_MI_APP_ARG_APP_LOG, "--log\n\tUse this argument to tell the MI Driver to update it's log\n\tfile '%s'."},
+ {IDE_MI_APP_ARG_APP_LOG_DIR, "--log-dir\n\tUse this argument to specify the directory the MI Driver\n\twill place the log file in, i.e --log-dir=/tmp." },
{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'"},
@@ -103,7 +88,6 @@ const CMICmnResources::SRsrcTextData CMICmnResources::ms_pResourceId2TextData[]
{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"},
@@ -143,7 +127,7 @@ const CMICmnResources::SRsrcTextData CMICmnResources::ms_pResourceId2TextData[]
{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_CLIENTNOTREGISTERED, "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'"},
@@ -196,9 +180,7 @@ const CMICmnResources::SRsrcTextData CMICmnResources::ms_pResourceId2TextData[]
{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"},
@@ -225,6 +207,7 @@ const CMICmnResources::SRsrcTextData CMICmnResources::ms_pResourceId2TextData[]
{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_LLDBPROCESS_DESTROY, "Command '%s'. Process destroy 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"},
@@ -236,6 +219,7 @@ const CMICmnResources::SRsrcTextData CMICmnResources::ms_pResourceId2TextData[]
{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_LOCATION_NOT_FOUND, "Command '%s'. Breakpoint location '%s' not found"},
{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"},
@@ -246,23 +230,33 @@ const CMICmnResources::SRsrcTextData CMICmnResources::ms_pResourceId2TextData[]
{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_VARIABLE_CHILD_RANGE_INVALID, "Command '%s'. Variable children range invalid"},
{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_LLDB_ERR_NOT_READ_WHOLE_BLK, "Command '%s'. LLDB unable to read entire memory block of %u bytes at address 0x%016" PRIx64 },
+ {IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES, "Command '%s'. Unable to read memory block of %u bytes at address 0x%016" PRIx64 ": %s "},
{IDS_CMD_ERR_INVALID_PROCESS, "Command '%s'. Invalid process during debug session"},
- {IDS_CMD_ERR_INVALID_PRINT_VALUES, "Command '%s'. Unknown value for PRINT_VALUES: must be: 0 or \"--no-values\", 1 or \"all-values\", 2 or \"simple-values\""},
+ {IDS_CMD_ERR_INVALID_PRINT_VALUES, "Command '%s'. Unknown value for PRINT_VALUES: must be: 0 or \"--no-values\", 1 or \"--all-values\", 2 or \"--simple-values\""},
+ {IDS_CMD_ERR_INVALID_LOCATION_FORMAT, "Command '%s'. Invalid location format '%s'"},
{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_LLDB_ERR_WRITE_MEM_BYTES, "Command '%s'. Unable to write memory block of %u bytes at address 0x%016" PRIx64 ": %s "},
+ {IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK, "Command '%s'. LLDB unable to write entire memory block of %u bytes at address 0x%016" PRIX64},
{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_NOT_FOUND, "The request '%s' was not recognised, 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"}};
+ {IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC, "'target-async' expects \"on\" or \"off\""},
+ {IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH, "'solib-search-path' requires at least one argument"},
+ {IDS_CMD_ERR_GDBSET_OPT_PRINT_BAD_ARGS, "'print' expects option-name and \"on\" or \"off\""},
+ {IDS_CMD_ERR_GDBSET_OPT_PRINT_UNKNOWN_OPTION, "'print' error. The option '%s' not found"},
+ {IDS_CMD_ERR_GDBSHOW_OPT_PRINT_BAD_ARGS, "'print' expects option-name and \"on\" or \"off\""},
+ {IDS_CMD_ERR_GDBSHOW_OPT_PRINT_UNKNOWN_OPTION, "'print' error. The option '%s' not found"},
+ {IDS_CMD_ERR_EXPR_INVALID, "Failed to evaluate expression: %s"},
+ {IDS_CMD_ERR_ATTACH_FAILED, "Command '%s'. Attach to processs failed: %s"},
+ {IDS_CMD_ERR_ATTACH_BAD_ARGS, "Command '%s'. Must specify either a PID or a Name"}};
//++ ------------------------------------------------------------------------------------
// Details: CMICmnResources constructor.
@@ -391,7 +385,7 @@ CMICmnResources::HasString(const MIuint vResourceId) const
}
//++ ------------------------------------------------------------------------------------
-// Details: Retrieve the resource text data for the given resource ID. If a resourse ID
+// Details: Retrieve the resource text data for the given resource ID. If a resource ID
// cannot be found and error is given returning the ID of the resource that
// cannot be located.
// Type: Method.
@@ -428,7 +422,7 @@ CMICmnResources::GetStringFromResource(const MIuint vResourceId, CMIUtilString &
const MIuint nRsrcId((*it).first);
MIunused(nRsrcId);
- const MIchar *pRsrcData((*it).second);
+ const char *pRsrcData((*it).second);
// Return result
vrwResourceString = pRsrcData;
diff --git a/tools/lldb-mi/MICmnResources.h b/tools/lldb-mi/MICmnResources.h
index b561473fbb79..7e5b70fcbdd2 100644
--- a/tools/lldb-mi/MICmnResources.h
+++ b/tools/lldb-mi/MICmnResources.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
@@ -77,10 +65,6 @@ enum
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,
@@ -89,7 +73,9 @@ enum
IDE_MI_APP_ARG_VERSION_LONG,
IDE_MI_APP_ARG_INTERPRETER,
IDE_MI_APP_ARG_EXECUTEABLE,
+ IDE_MI_APP_ARG_SOURCE,
IDE_MI_APP_ARG_APP_LOG,
+ IDE_MI_APP_ARG_APP_LOG_DIR,
IDE_MI_APP_ARG_EXAMPLE,
IDE_MI_APP_ARG_EXECUTABLE,
@@ -116,8 +102,6 @@ enum
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,
@@ -154,7 +138,7 @@ enum
IDS_LLDBDEBUGGER_ERR_THREAD_DELETE,
IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER,
IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME,
- IDS_LLDBDEBUGGER_ERR_CLIENTNOTREGISTERD,
+ IDS_LLDBDEBUGGER_ERR_CLIENTNOTREGISTERED,
IDS_LLDBDEBUGGER_ERR_STOPLISTENER,
IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME,
IDS_LLDBDEBUGGER_WRN_UNKNOWN_EVENT,
@@ -208,10 +192,8 @@ enum
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,
@@ -241,6 +223,7 @@ enum
IDS_CMD_ERR_FNFAILED,
IDS_CMD_ERR_SHARED_DATA_NOT_FOUND,
IDS_CMD_ERR_LLDBPROCESS_DETACH,
+ IDS_CMD_ERR_LLDBPROCESS_DESTROY,
IDS_CMD_ERR_SETWKDIR,
IDS_CMD_ERR_INVALID_TARGET,
IDS_CMD_ERR_INVALID_TARGET_CURRENT,
@@ -252,6 +235,7 @@ enum
IDS_CMD_ERR_NOT_IMPLEMENTED_DEPRECATED,
IDS_CMD_ERR_CREATE_TARGET,
IDS_CMD_ERR_BRKPT_LOCATION_FORMAT,
+ IDS_CMD_ERR_BRKPT_LOCATION_NOT_FOUND,
IDS_CMD_ERR_BRKPT_INVALID,
IDS_CMD_ERR_BRKPT_CNT_EXCEEDED,
IDS_CMD_ERR_SOME_ERROR,
@@ -262,6 +246,7 @@ enum
IDS_CMD_ERR_VARIABLE_ENUM_INVALID,
IDS_CMD_ERR_VARIABLE_EXPRESSIONPATH,
IDS_CMD_ERR_VARIABLE_CREATION_FAILED,
+ IDS_CMD_ERR_VARIABLE_CHILD_RANGE_INVALID,
IDS_CMD_ERR_CMD_RUN_BUT_NO_ACTION,
IDS_CMD_ERR_EVENT_HANDLED_BUT_NO_ACTION,
IDS_CMD_ERR_DISASM_ADDR_START_INVALID,
@@ -271,6 +256,7 @@ enum
IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES,
IDS_CMD_ERR_INVALID_PROCESS,
IDS_CMD_ERR_INVALID_PRINT_VALUES,
+ IDS_CMD_ERR_INVALID_LOCATION_FORMAT,
IDS_CMD_ERR_INVALID_FORMAT_TYPE,
IDS_CMD_ERR_BRKPT_INFO_OBJ_NOT_FOUND,
IDS_CMD_ERR_LLDB_ERR_WRITE_MEM_BYTES,
@@ -278,7 +264,15 @@ enum
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
+ IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC,
+ IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH,
+ IDS_CMD_ERR_GDBSET_OPT_PRINT_BAD_ARGS,
+ IDS_CMD_ERR_GDBSET_OPT_PRINT_UNKNOWN_OPTION,
+ IDS_CMD_ERR_GDBSHOW_OPT_PRINT_BAD_ARGS,
+ IDS_CMD_ERR_GDBSHOW_OPT_PRINT_UNKNOWN_OPTION,
+ IDS_CMD_ERR_EXPR_INVALID,
+ IDS_CMD_ERR_ATTACH_FAILED,
+ IDS_CMD_ERR_ATTACH_BAD_ARGS
};
//++ ============================================================================
@@ -303,8 +297,8 @@ class CMICmnResources : public CMICmnBase, public MI::ISingleton<CMICmnResources
// Typedef:
private:
- typedef std::map<MIuint, const MIchar *> MapRscrIdToTextData_t;
- typedef std::pair<MIuint, const MIchar *> MapPairRscrIdToTextData_t;
+ typedef std::map<MIuint, const char *> MapRscrIdToTextData_t;
+ typedef std::pair<MIuint, const char *> MapPairRscrIdToTextData_t;
// Enumerations:
private:
@@ -318,7 +312,7 @@ class CMICmnResources : public CMICmnBase, public MI::ISingleton<CMICmnResources
struct SRsrcTextData
{
MIuint id;
- const MIchar *pTextData;
+ const char *pTextData;
};
// Methods:
diff --git a/tools/lldb-mi/MICmnStreamStderr.cpp b/tools/lldb-mi/MICmnStreamStderr.cpp
index cd09e8fc33d0..74f36121ee63 100644
--- a/tools/lldb-mi/MICmnStreamStderr.cpp
+++ b/tools/lldb-mi/MICmnStreamStderr.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmnStreamStderr.h b/tools/lldb-mi/MICmnStreamStderr.h
index 4fc363fa6b0a..4f4874ebc9bc 100644
--- a/tools/lldb-mi/MICmnStreamStderr.h
+++ b/tools/lldb-mi/MICmnStreamStderr.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MICmnStreamStdin.cpp b/tools/lldb-mi/MICmnStreamStdin.cpp
index 2d54921d323c..891b1c9bb994 100644
--- a/tools/lldb-mi/MICmnStreamStdin.cpp
+++ b/tools/lldb-mi/MICmnStreamStdin.cpp
@@ -7,32 +7,19 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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.
-//--
+// Third Party Headers
+#ifdef _MSC_VER
+#include <Windows.h>
+#endif
+#include <string.h> // For std::strerror()
// 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 )
+#include "MIUtilSingletonHelper.h"
//++ ------------------------------------------------------------------------------------
// Details: CMICmnStreamStdin constructor.
@@ -42,13 +29,9 @@
// 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)
+ : m_strPromptCurrent("(gdb)")
+ , m_bShowPrompt(true)
+ , m_pCmdBuffer(nullptr)
{
}
@@ -86,37 +69,19 @@ CMICmnStreamStdin::Initialize(void)
// 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_pCmdBuffer = new char[m_constBufferSize];
}
-
- m_bInitialized = bOk;
-
- if (!bOk)
+ else
{
CMIUtilString strInitError(CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_STREAMSTDIN), errMsg.c_str()));
SetErrorDescription(strInitError);
+
return MIstatus::failure;
}
+ m_bInitialized = bOk;
return MIstatus::success;
}
@@ -142,19 +107,15 @@ CMICmnStreamStdin::Shutdown(void)
ClrErrorDescription();
+ if (m_pCmdBuffer != nullptr)
+ {
+ delete[] m_pCmdBuffer;
+ m_pCmdBuffer = nullptr;
+ }
+
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);
@@ -203,23 +164,6 @@ CMICmnStreamStdin::GetPrompt(void) const
}
//++ ------------------------------------------------------------------------------------
-// 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.
@@ -251,199 +195,47 @@ CMICmnStreamStdin::GetEnablePrompt(void) const
}
//++ ------------------------------------------------------------------------------------
-// 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".
+// Details: Wait on new line of data from stdin stream (completed by '\n' or '\r').
// Type: Method.
-// vrwbYesAlive - (W) False = yes exit stdin monitoring, true = continue monitor.
-// Return: MIstatus::success - Functional succeeded.
-// MIstatus::failure - Functional failed.
+// Args: vwErrMsg - (W) Empty string ok or error description.
+// Return: char * - text buffer pointer or NULL on failure.
// Throws: None.
//--
-bool
-CMICmnStreamStdin::MonitorStdin(bool &vrwbYesAlive)
+const char *
+CMICmnStreamStdin::ReadLine(CMIUtilString &vwErrMsg)
{
- if (m_bShowPrompt)
- {
- CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance();
- rStdoutMan.WriteMIResponse(m_strPromptCurrent.c_str());
- m_bRedrawPrompt = false;
- }
+ vwErrMsg.clear();
- // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
- if (m_bKeyCtrlCHit)
+ // Read user input
+ const char *pText = ::fgets(&m_pCmdBuffer[0], m_constBufferSize, stdin);
+ if (pText == nullptr)
{
- CMIDriver &rMIDriver = CMIDriver::Instance();
- rMIDriver.SetExitApplicationFlag(false);
- if (rMIDriver.GetExitApplicationFlag())
+#ifdef _MSC_VER
+ // Was Ctrl-C hit?
+ // On Windows, Ctrl-C gives an ERROR_OPERATION_ABORTED as error on the command-line.
+ // The end-of-file indicator is also set, so without this check we will exit next if statement.
+ if (::GetLastError() == ERROR_OPERATION_ABORTED)
+ return nullptr;
+#endif
+ if (::feof(stdin))
{
- vrwbYesAlive = false;
- return MIstatus::success;
+ const bool bForceExit = true;
+ CMIDriver::Instance().SetExitApplicationFlag(bForceExit);
}
-
- // Reset - the MI Driver received SIGINT during a running debug programm session
- m_bKeyCtrlCHit = false;
+ else if (::ferror(stdin) != 0)
+ vwErrMsg = ::strerror(errno);
+ return nullptr;
}
-#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
+ // Strip off new line characters
+ for (char *pI = m_pCmdBuffer; *pI != '\0'; pI++)
{
- 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)
+ if ((*pI == '\n') || (*pI == '\r'))
{
- CMICmnStreamStdout::Instance().Write(stdinErrMsg);
+ *pI = '\0';
+ break;
}
- 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;
-}
-
-//++ ------------------------------------------------------------------------------------
-// Details: Do some actions before exiting.
-// Type: Method.
-// Args: None.
-// Return: None.
-// Throws: None.
-//--
-void
-CMICmnStreamStdin::OnExitHandler(void)
-{
- m_pStdinReadHandler->InterruptReadLine();
+ return pText;
}
diff --git a/tools/lldb-mi/MICmnStreamStdin.h b/tools/lldb-mi/MICmnStreamStdin.h
index a6779d531669..309c7d8eed2f 100644
--- a/tools/lldb-mi/MICmnStreamStdin.h
+++ b/tools/lldb-mi/MICmnStreamStdin.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -37,40 +25,11 @@
// 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>
+class CMICmnStreamStdin : public CMICmnBase, 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;
- virtual void InterruptReadLine(void){};
-
- /* dtor */ virtual ~IOSStdinHandler(void){};
- };
-
// Methods:
public:
bool Initialize(void);
@@ -80,22 +39,7 @@ class CMICmnStreamStdin : public CMICmnBase, public CMIUtilThreadActiveObjBase,
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);
- void OnExitHandler(void);
-
- // 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
+ const char *ReadLine(CMIUtilString &vwErrMsg);
// Methods:
private:
@@ -103,11 +47,6 @@ class CMICmnStreamStdin : public CMICmnBase, public CMIUtilThreadActiveObjBase,
/* 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
@@ -115,11 +54,8 @@ class CMICmnStreamStdin : public CMICmnBase, public CMIUtilThreadActiveObjBase,
// 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;
+ static const int m_constBufferSize = 2048;
+ char *m_pCmdBuffer;
};
diff --git a/tools/lldb-mi/MICmnStreamStdinLinux.cpp b/tools/lldb-mi/MICmnStreamStdinLinux.cpp
deleted file mode 100644
index 07e652d84c19..000000000000
--- a/tools/lldb-mi/MICmnStreamStdinLinux.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-//===-- 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(__APPLE__)
-#include <sys/select.h>
-#include <unistd.h> // For STDIN_FILENO
-#endif // defined( __APPLE__ )
-#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)
-{
-#if defined(__APPLE__)
- // The code below is needed on OSX where lldb-mi hangs when doing -exec-run.
- // The hang seems to come from calling fgets and fileno from different thread.
- // Although this problem was not observed on Linux.
- // A solution based on 'ioctl' was initially committed but it seems to make
- // lldb-mi takes much more processor time. The solution based on 'select' works
- // well but it seems to slow the execution of lldb-mi tests a lot on Linux.
- // As a result, this code is #defined to run only on OSX.
- fd_set setOfStdin;
- FD_ZERO(&setOfStdin);
- FD_SET(STDIN_FILENO, &setOfStdin);
-
- // Wait while input would be available
- if (::select(STDIN_FILENO + 1, &setOfStdin, nullptr, nullptr, nullptr) == -1)
- {
- vwbAvail = false;
- return MIstatus::failure;
- }
-
-#endif // defined( __APPLE__ )
- vwbAvail = true;
- 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;
-}
-
-//++ ------------------------------------------------------------------------------------
-// Details: Interrupt current and prevent new ReadLine operations.
-// Type: Method.
-// Args: None.
-// Return: None.
-// Throws: None.
-//--
-void
-CMICmnStreamStdinLinux::InterruptReadLine(void)
-{
- fclose(stdin);
-}
diff --git a/tools/lldb-mi/MICmnStreamStdinLinux.h b/tools/lldb-mi/MICmnStreamStdinLinux.h
deleted file mode 100644
index edac94034f57..000000000000
--- a/tools/lldb-mi/MICmnStreamStdinLinux.h
+++ /dev/null
@@ -1,72 +0,0 @@
-//===-- 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);
- virtual void InterruptReadLine(void);
-
- // 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
deleted file mode 100644
index 8d5a3e8aa7c9..000000000000
--- a/tools/lldb-mi/MICmnStreamStdinWindows.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-//===-- 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;
-}
diff --git a/tools/lldb-mi/MICmnStreamStdinWindows.h b/tools/lldb-mi/MICmnStreamStdinWindows.h
deleted file mode 100644
index 40e4e8546fe4..000000000000
--- a/tools/lldb-mi/MICmnStreamStdinWindows.h
+++ /dev/null
@@ -1,79 +0,0 @@
-//===-- 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
index e32d4fca2446..63dec65a7753 100644
--- a/tools/lldb-mi/MICmnStreamStdout.cpp
+++ b/tools/lldb-mi/MICmnStreamStdout.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -168,11 +156,9 @@ CMICmnStreamStdout::WritePriv(const CMIUtilString &vText, const CMIUtilString &v
// Send this text to stdout
const MIint 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);
+ // Don't call the CMICmnBase::SetErrorDescription() because it will cause a stack overflow:
+ // CMICmnBase::SetErrorDescription -> CMICmnStreamStdout::Write -> CMICmnStreamStdout::WritePriv -> CMICmnBase::SetErrorDescription
bOk = MIstatus::failure;
- }
else
{
::fprintf(stdout, "\n");
@@ -230,9 +216,23 @@ CMICmnStreamStdout::Unlock(void)
bool
CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt)
{
- const bool bLock = CMICmnStreamStdout::Instance().Lock();
- const bool bOk = bLock && CMICmnStreamStdout::Instance().WriteMIResponse(vrTxt);
- bLock &&CMICmnStreamStdout::Instance().Unlock();
+ const bool bSendToLog = true;
+ return CMICmnStreamStdout::Instance().WriteMIResponse(vrTxt, bSendToLog);
+}
- return bOk;
+//++ ------------------------------------------------------------------------------------
+// Details: Write prompt to stdout if it's enabled.
+// Type: Static method.
+// Args: None.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMICmnStreamStdout::WritePrompt(void)
+{
+ const CMICmnStreamStdin &rStdinMan = CMICmnStreamStdin::Instance();
+ if (rStdinMan.GetEnablePrompt())
+ return TextToStdout(rStdinMan.GetPrompt());
+ return MIstatus::success;
}
diff --git a/tools/lldb-mi/MICmnStreamStdout.h b/tools/lldb-mi/MICmnStreamStdout.h
index 677a5c4a1868..526a322f6e35 100644
--- a/tools/lldb-mi/MICmnStreamStdout.h
+++ b/tools/lldb-mi/MICmnStreamStdout.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -43,6 +31,7 @@ class CMICmnStreamStdout : public CMICmnBase, public MI::ISingleton<CMICmnStream
// Statics:
public:
static bool TextToStdout(const CMIUtilString &vrTxt);
+ static bool WritePrompt(void);
// Methods:
public:
diff --git a/tools/lldb-mi/MICmnThreadMgrStd.cpp b/tools/lldb-mi/MICmnThreadMgrStd.cpp
index 8fa30125b832..f0185b8fcf1d 100644
--- a/tools/lldb-mi/MICmnThreadMgrStd.cpp
+++ b/tools/lldb-mi/MICmnThreadMgrStd.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MICmnThreadMgrStd.h b/tools/lldb-mi/MICmnThreadMgrStd.h
index 598c98a9def3..8f2d207995c6 100644
--- a/tools/lldb-mi/MICmnThreadMgrStd.h
+++ b/tools/lldb-mi/MICmnThreadMgrStd.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MIDataTypes.h b/tools/lldb-mi/MIDataTypes.h
index aced1c66f8d9..b0583343ab3c 100644
--- a/tools/lldb-mi/MIDataTypes.h
+++ b/tools/lldb-mi/MIDataTypes.h
@@ -7,21 +7,11 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
@@ -86,9 +76,6 @@ typedef unsigned int MIuint;
// 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.
diff --git a/tools/lldb-mi/MIDriver.cpp b/tools/lldb-mi/MIDriver.cpp
index 5628e344952b..549f9e255790 100644
--- a/tools/lldb-mi/MIDriver.cpp
+++ b/tools/lldb-mi/MIDriver.cpp
@@ -7,25 +7,11 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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 <fstream>
#include "lldb/API/SBError.h"
// In-house headers:
-#include "Driver.h"
#include "MIDriver.h"
#include "MICmnResources.h"
#include "MICmnLog.h"
@@ -69,6 +55,7 @@ CMIDriver::CMIDriver(void)
, m_eCurrentDriverState(eDriverState_NotRunning)
, m_bHaveExecutableFileNamePathOnCmdLine(false)
, m_bDriverDebuggingArgExecutable(false)
+ , m_bHaveCommandFileNamePathOnCmdLine(false)
{
}
@@ -86,7 +73,7 @@ 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).
+// (if *this driver decides it can't handle the command).
// Type: Method.
// Args: vbYes - (R) True = yes fall through, false = do not pass on command.
// Return: MIstatus::success - Functional succeeded.
@@ -103,7 +90,7 @@ CMIDriver::SetEnableFallThru(const bool vbYes)
//++ ------------------------------------------------------------------------------------
// 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).
+// (if *this driver decides it can't handle the command).
// Type: Method.
// Args: None.
// Return: bool - True = yes fall through, false = do not pass on command.
@@ -187,22 +174,6 @@ CMIDriver::Initialize(void)
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;
@@ -340,20 +311,6 @@ CMIDriver::GetError(void) const
}
//++ ------------------------------------------------------------------------------------
-// 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.
@@ -413,16 +370,16 @@ CMIDriver::DoParseArgs(const int argc, const char *argv[], FILE *vpStdOut, bool
// 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
+// --executable <file>
+// --source <file> or -s <file>
// 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
+// The --executable is necessary to differentiate whether the MI Driver is being
+// used by a client (e.g. 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.
+// executable if called from the command line. Using --executable tells the MI Driver
+// it is being called from the command line and to prepare to launch the executable
+// argument for a debug session. Using --interpreter on the command line does not
+// issue additional commands to initialise a debug session.
// 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.
@@ -452,20 +409,40 @@ CMIDriver::ParseArgs(const int argc, const char *argv[], FILE *vpStdOut, bool &v
if (bHaveArgs)
{
- // Search right to left to look for the executable
+ // Search right to left to look for filenames
for (MIint i = argc - 1; i > 0; i--)
{
const CMIUtilString strArg(argv[i]);
const CMICmdArgValFile argFile;
+
+ // Check for a filename
if (argFile.IsFilePath(strArg) || CMICmdArgValString(true, false, true).IsStringArg(strArg))
{
+ // Is this the command file for the '-s' or '--source' options?
+ const CMIUtilString strPrevArg(argv[i - 1]);
+ if (strPrevArg.compare("-s") == 0 || strPrevArg.compare("--source") == 0)
+ {
+ m_strCmdLineArgCommandFileNamePath = strArg;
+ m_bHaveCommandFileNamePathOnCmdLine = true;
+ i--; // skip '-s' on the next loop
+ continue;
+ }
+ // Else, must be the executable
bHaveExecutableFileNamePath = true;
- m_strCmdLineArgExecuteableFileNamePath = argFile.GetFileNamePath(strArg);
+ m_strCmdLineArgExecuteableFileNamePath = 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.
+ // Report error if no command file was specified for the '-s' or '--source' options
+ else if (strArg.compare("-s") == 0 || strArg.compare("--source") == 0)
+ {
+ vwbExiting = true;
+ const CMIUtilString errMsg = CMIUtilString::Format(MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF), strArg.c_str());
+ errStatus.SetErrorString(errMsg.c_str());
+ break;
+ }
+ // This argument is also checked for in CMIDriverMgr::ParseArgs()
+ else if (strArg.compare("--executable") == 0) // Used to specify that there is executable argument also on the command line
+ { // See fn description.
bHaveExecutableLongOption = true;
}
}
@@ -473,13 +450,7 @@ CMIDriver::ParseArgs(const int argc, const char *argv[], FILE *vpStdOut, bool &v
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;
@@ -500,42 +471,6 @@ CMIDriver::GetDriverIsGDBMICompatibleDriver(void) const
}
//++ ------------------------------------------------------------------------------------
-// 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.
@@ -551,16 +486,6 @@ CMIDriver::StartWorkerThreads(void)
// 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))
{
@@ -609,29 +534,53 @@ CMIDriver::DoMainLoop(void)
if (!StartWorkerThreads())
return MIstatus::failure;
- // App is not quitting currently
- m_bExitApp = false;
+ bool bOk = MIstatus::success;
-// CODETAG_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
-#if MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
if (HaveExecutableFileNamePathOnCmdLine())
{
- if (!LocalDebugSessionStartupInjectCommands())
+ if (!LocalDebugSessionStartupExecuteCommands())
{
SetErrorDescription(MIRSRC(IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION));
- return MIstatus::failure;
+ bOk = MIstatus::failure;
}
}
-#endif // MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
+
+ // App is not quitting currently
+ m_bExitApp = false;
+
+ // Handle source file
+ if (m_bHaveCommandFileNamePathOnCmdLine)
+ {
+ const bool bAsyncMode = false;
+ ExecuteCommandFile(bAsyncMode);
+ }
// While the app is active
- while (!m_bExitApp)
+ while (bOk && !m_bExitApp)
{
- // Poll stdin queue and dispatch
- if (!ReadStdinLineQueue())
+ CMIUtilString errorText;
+ const char *pCmd = m_rStdin.ReadLine (errorText);
+ if (pCmd != nullptr)
{
- // Something went wrong
- break;
+ CMIUtilString lineText(pCmd);
+ if (!lineText.empty ())
+ {
+ // Check that the handler thread is alive (otherwise we stuck here)
+ assert(CMICmnLLDBDebugger::Instance().ThreadIsActive());
+
+ {
+ // Lock Mutex before processing commands so that we don't disturb an event
+ // being processed
+ CMIUtilThreadLock lock(CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex());
+ bOk = InterpretCommand(lineText);
+ }
+
+ // Draw prompt if desired
+ bOk = bOk && CMICmnStreamStdout::WritePrompt();
+
+ // Wait while the handler thread handles incoming events
+ CMICmnLLDBDebugger::Instance().WaitForHandleEvent();
+ }
}
}
@@ -648,72 +597,6 @@ CMIDriver::DoMainLoop(void)
}
//++ ------------------------------------------------------------------------------------
-// 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
- bool bOk = false;
- {
- // Lock Mutex before processing commands so that we don't disturb an event
- // that is being processed.
- CMIUtilThreadLock lock(CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex());
- 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.
@@ -766,8 +649,8 @@ CMIDriver::InterpretCommandFallThruDriver(const CMIUtilString &vTextLine, bool &
// 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 char * pName = pOtherDriver->GetDriverName().c_str();
+ // const char * 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 );
@@ -926,42 +809,6 @@ CMIDriver::GetId(void) const
}
//++ ------------------------------------------------------------------------------------
-// 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
@@ -976,15 +823,92 @@ CMIDriver::QueueMICommand(const CMIUtilString &vMICmd)
bool
CMIDriver::InterpretCommand(const CMIUtilString &vTextLine)
{
+ const bool bNeedToRebroadcastStopEvent = m_rLldbDebugger.CheckIfNeedToRebroadcastStopEvent();
bool bCmdYesValid = false;
bool bOk = InterpretCommandThisDriver(vTextLine, bCmdYesValid);
if (bOk && !bCmdYesValid)
bOk = InterpretCommandFallThruDriver(vTextLine, bCmdYesValid);
+ if (bNeedToRebroadcastStopEvent)
+ m_rLldbDebugger.RebroadcastStopEvent();
+
return bOk;
}
//++ ------------------------------------------------------------------------------------
+// Details: Helper function for CMIDriver::InterpretCommandThisDriver.
+// Convert a CLI command to MI command (just wrap any CLI command
+// into "<tokens>-interpreter-exec command \"<CLI command>\"").
+// Type: Method.
+// Args: vTextLine - (R) Text data representing a possible command.
+// Return: CMIUtilString - The original MI command or converted CLI command.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+CMIUtilString
+CMIDriver::WrapCLICommandIntoMICommand(const CMIUtilString &vTextLine) const
+{
+ // Tokens contain following digits
+ static const CMIUtilString digits("0123456789");
+
+ // Consider an algorithm on the following example:
+ // 001-file-exec-and-symbols "/path/to/file"
+ //
+ // 1. Skip a command token
+ // For example:
+ // 001-file-exec-and-symbols "/path/to/file"
+ // 001target create "/path/to/file"
+ // ^ -- command starts here (in both cases)
+ // Also possible case when command not found:
+ // 001
+ // ^ -- i.e. only tokens are present (or empty string at all)
+ const size_t nCommandOffset = vTextLine.find_first_not_of(digits);
+
+ // 2. Check if command is empty
+ // For example:
+ // 001-file-exec-and-symbols "/path/to/file"
+ // 001target create "/path/to/file"
+ // ^ -- command not empty (in both cases)
+ // or:
+ // 001
+ // ^ -- command wasn't found
+ const bool bIsEmptyCommand = (nCommandOffset == CMIUtilString::npos);
+
+ // 3. Check and exit if it isn't a CLI command
+ // For example:
+ // 001-file-exec-and-symbols "/path/to/file"
+ // 001
+ // ^ -- it isn't CLI command (in both cases)
+ // or:
+ // 001target create "/path/to/file"
+ // ^ -- it's CLI command
+ const bool bIsCliCommand = !bIsEmptyCommand && (vTextLine.at(nCommandOffset) != '-');
+ if (!bIsCliCommand)
+ return vTextLine;
+
+ // 4. Wrap CLI command to make it MI-compatible
+ //
+ // 001target create "/path/to/file"
+ // ^^^ -- token
+ const std::string vToken(vTextLine.begin(), vTextLine.begin() + nCommandOffset);
+ // 001target create "/path/to/file"
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- CLI command
+ const CMIUtilString vCliCommand(std::string(vTextLine, nCommandOffset).c_str());
+
+ // 5. Escape special characters and embed the command in a string
+ // Result: it looks like -- target create \"/path/to/file\".
+ const std::string vShieldedCliCommand(vCliCommand.AddSlashes());
+
+ // 6. Turn the CLI command into an MI command, as in:
+ // 001-interpreter-exec command "target create \"/path/to/file\""
+ // ^^^ -- token
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ -- wrapper
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- shielded CLI command
+ return CMIUtilString::Format("%s-interpreter-exec command \"%s\"",
+ vToken.c_str(), vShieldedCliCommand.c_str());
+}
+
+//++ ------------------------------------------------------------------------------------
// 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
@@ -992,7 +916,7 @@ CMIDriver::InterpretCommand(const CMIUtilString &vTextLine)
// 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.
+// vwbCmdYesValid - (W) True = Command valid, false = command not handled.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
@@ -1000,12 +924,14 @@ CMIDriver::InterpretCommand(const CMIUtilString &vTextLine)
bool
CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine, bool &vwbCmdYesValid)
{
- vwbCmdYesValid = false;
+ // Convert any CLI commands into MI commands
+ CMIUtilString vMITextLine(WrapCLICommandIntoMICommand(vTextLine));
+ vwbCmdYesValid = false;
bool bCmdNotInCmdFactor = false;
SMICmdData cmdData;
CMICmdMgr &rCmdMgr = CMICmdMgr::Instance();
- if (!rCmdMgr.CmdInterpret(vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData))
+ if (!rCmdMgr.CmdInterpret(vMITextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData))
return MIstatus::failure;
if (vwbCmdYesValid)
@@ -1018,13 +944,13 @@ CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine, bool &vwbC
// 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)
+ // has been given to the driver to try and interpret.
+ if (vMITextLine.at(0) == 27)
{
CMIUtilString logInput(MIRSRC(IDS_STDIN_INPUT_CTRL_CHARS));
- for (MIuint i = 0; i < vTextLine.length(); i++)
+ for (MIuint i = 0; i < vMITextLine.length(); i++)
{
- logInput += CMIUtilString::Format("%d ", vTextLine.at(i));
+ logInput += CMIUtilString::Format("%d ", vMITextLine.at(i));
}
m_pLog->WriteLog(logInput);
return MIstatus::success;
@@ -1037,14 +963,14 @@ CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine, bool &vwbC
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()));
+ CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vMITextLine.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());
+ const bool bOk = m_rStdOut.WriteMIResponse(miResultRecord.GetString());
// Proceed to wait for or execute next command
- return MIstatus::success;
+ return bOk;
}
//++ ------------------------------------------------------------------------------------
@@ -1082,7 +1008,6 @@ CMIDriver::SetExitApplicationFlag(const bool vbForceExit)
{
CMIUtilThreadLock lock(m_threadMutex);
m_bExitApp = true;
- m_rStdin.OnExitHandler();
return;
}
@@ -1092,12 +1017,11 @@ CMIDriver::SetExitApplicationFlag(const bool vbForceExit)
// but halt the inferior program being debugged instead
if (m_eCurrentDriverState == eDriverState_RunningDebugging)
{
- InjectMICommand("-exec-interrupt");
+ InterpretCommand("-exec-interrupt");
return;
}
m_bExitApp = true;
- m_rStdin.OnExitHandler();
}
//++ ------------------------------------------------------------------------------------
@@ -1252,9 +1176,7 @@ CMIDriver::InitClientIDEToMIDriver(void) const
bool
CMIDriver::InitClientIDEEclipse(void) const
{
- std::cout << "(gdb)" << std::endl;
-
- return MIstatus::success;
+ return CMICmnStreamStdout::WritePrompt();
}
//++ ------------------------------------------------------------------------------------
@@ -1299,11 +1221,13 @@ CMIDriver::GetExecutableFileNamePathOnCmdLine(void) const
// Throws: None.
//--
bool
-CMIDriver::LocalDebugSessionStartupInjectCommands(void)
+CMIDriver::LocalDebugSessionStartupExecuteCommands(void)
{
- const CMIUtilString strCmd(CMIUtilString::Format("-file-exec-and-symbols %s", m_strCmdLineArgExecuteableFileNamePath.c_str()));
-
- return InjectMICommand(strCmd);
+ const CMIUtilString strCmd(CMIUtilString::Format("-file-exec-and-symbols \"%s\"", m_strCmdLineArgExecuteableFileNamePath.AddSlashes().c_str()));
+ bool bOk = CMICmnStreamStdout::TextToStdout(strCmd);
+ bOk = bOk && InterpretCommand(strCmd);
+ bOk = bOk && CMICmnStreamStdout::WritePrompt();
+ return bOk;
}
//++ ------------------------------------------------------------------------------------
@@ -1334,3 +1258,86 @@ CMIDriver::IsDriverDebuggingArgExecutable(void) const
{
return m_bDriverDebuggingArgExecutable;
}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Execute commands from command source file in specified mode, and
+// set exit-flag if needed.
+// Type: Method.
+// Args: vbAsyncMode - (R) True = execute commands in asynchronous mode, false = otherwise.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool
+CMIDriver::ExecuteCommandFile(const bool vbAsyncMode)
+{
+ std::ifstream ifsStartScript(m_strCmdLineArgCommandFileNamePath.c_str());
+ if (!ifsStartScript.is_open())
+ {
+ const CMIUtilString errMsg(
+ CMIUtilString::Format(MIRSRC(IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN), m_strCmdLineArgCommandFileNamePath.c_str()));
+ SetErrorDescription(errMsg.c_str());
+ const bool bForceExit = true;
+ SetExitApplicationFlag(bForceExit);
+ return MIstatus::failure;
+ }
+
+ // Switch lldb to synchronous mode
+ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+ const bool bAsyncSetting = rSessionInfo.GetDebugger().GetAsync();
+ rSessionInfo.GetDebugger().SetAsync(vbAsyncMode);
+
+ // Execute commands from file
+ bool bOk = MIstatus::success;
+ CMIUtilString strCommand;
+ while (!m_bExitApp && std::getline(ifsStartScript, strCommand))
+ {
+ // Print command
+ bOk = CMICmnStreamStdout::TextToStdout(strCommand);
+
+ // Skip if it's a comment or empty line
+ if (strCommand.empty() || strCommand[0] == '#')
+ continue;
+
+ // Execute if no error
+ if (bOk)
+ {
+ CMIUtilThreadLock lock(rSessionInfo.GetSessionMutex());
+ bOk = InterpretCommand(strCommand);
+ }
+
+ // Draw the prompt after command will be executed (if enabled)
+ bOk = bOk && CMICmnStreamStdout::WritePrompt();
+
+ // Exit if there is an error
+ if (!bOk)
+ {
+ const bool bForceExit = true;
+ SetExitApplicationFlag(bForceExit);
+ break;
+ }
+
+ // Wait while the handler thread handles incoming events
+ CMICmnLLDBDebugger::Instance().WaitForHandleEvent();
+ }
+
+ // Switch lldb back to initial mode
+ rSessionInfo.GetDebugger().SetAsync(bAsyncSetting);
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Gets called when lldb-mi gets a signal. Stops the process if it was SIGINT.
+//
+// Type: Method.
+// Args: signal that was delivered
+// Return: None.
+// Throws: None.
+//--
+void
+CMIDriver::DeliverSignal(int signal)
+{
+ if (signal == SIGINT && (m_eCurrentDriverState == eDriverState_RunningDebugging))
+ InterpretCommand("-exec-interrupt");
+}
diff --git a/tools/lldb-mi/MIDriver.h b/tools/lldb-mi/MIDriver.h
index dafe1bedcf01..795549e0f4a0 100644
--- a/tools/lldb-mi/MIDriver.h
+++ b/tools/lldb-mi/MIDriver.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
@@ -51,7 +39,6 @@ class CMICmnStreamStdout;
class CMIDriver : public CMICmnBase,
public CMIDriverMgr::IDriver,
public CMIDriverBase,
- public CMICmnStreamStdin::IStreamStdin,
public MI::ISingleton<CMIDriver>
{
friend class MI::ISingleton<CMIDriver>;
@@ -101,7 +88,6 @@ class CMIDriver : public CMICmnBase,
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;
@@ -111,7 +97,6 @@ class CMIDriver : public CMICmnBase,
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;
@@ -128,8 +113,7 @@ class CMIDriver : public CMICmnBase,
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);
+ virtual void DeliverSignal(int signal);
// Typedefs:
private:
@@ -142,18 +126,18 @@ class CMIDriver : public CMICmnBase,
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);
+ CMIUtilString WrapCLICommandIntoMICommand(const CMIUtilString &vTextLine) const;
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);
+ bool LocalDebugSessionStartupExecuteCommands(void);
+ bool ExecuteCommandFile(const bool vbAsyncMode);
// Overridden:
private:
@@ -168,15 +152,16 @@ class CMIDriver : public CMICmnBase,
//
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
+ 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
+ bool m_bDriverDebuggingArgExecutable; // True = the MI Driver (MI mode) is debugging executable passed as argument,
+ // false = running via a client (e.g. Eclipse)
+ bool m_bHaveCommandFileNamePathOnCmdLine; // True = file with initial commands given as one of the parameters to the MI Driver, false = not found
+ CMIUtilString m_strCmdLineArgCommandFileNamePath;
};
diff --git a/tools/lldb-mi/MIDriverBase.cpp b/tools/lldb-mi/MIDriverBase.cpp
index fd1a0eca5536..e03e7b0abee8 100644
--- a/tools/lldb-mi/MIDriverBase.cpp
+++ b/tools/lldb-mi/MIDriverBase.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MIDriverBase.h b/tools/lldb-mi/MIDriverBase.h
index 25ac23887282..ad242116b5f0 100644
--- a/tools/lldb-mi/MIDriverBase.h
+++ b/tools/lldb-mi/MIDriverBase.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MIDriverMain.cpp b/tools/lldb-mi/MIDriverMain.cpp
index 5557799d3680..3b7588ba5df0 100644
--- a/tools/lldb-mi/MIDriverMain.cpp
+++ b/tools/lldb-mi/MIDriverMain.cpp
@@ -7,9 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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.
@@ -23,25 +20,7 @@
// 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
@@ -54,51 +33,17 @@
// 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)
-{
-#ifdef _WIN32 // Restore handler as it is not persistent on Windows
- signal(SIGWINCH, sigwinch_handler);
-#endif
- 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
@@ -130,74 +75,8 @@ sigint_handler(int vSigno)
}
}
- 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)
-{
-#ifdef _WIN32 // Restore handler as it is not persistent on Windows
- signal(SIGTSTP, sigtstp_handler);
-#endif
- 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)
-{
-#ifdef _WIN32 // Restore handler as it is not persistent on Windows
- signal(SIGCONT, sigcont_handler);
-#endif
- 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();
+ // Send signal to driver so that it can take suitable action
+ rDriverMgr.DeliverSignal (vSigno);
}
//++ ------------------------------------------------------------------------------------
@@ -213,13 +92,6 @@ 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();
@@ -248,66 +120,9 @@ DriverSystemShutdown(const bool vbAppExitOk)
// *** 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.
@@ -328,7 +143,6 @@ sigcont_handler(int signo)
// -1000 = Program failed did not initailize successfully.
// Throws: None.
//--
-#if MICONFIG_COMPILE_MIDRIVER_VERSION
int
main(int argc, char const *argv[])
{
@@ -349,11 +163,7 @@ main(int argc, char const *argv[])
}
// 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();
@@ -370,42 +180,3 @@ main(int argc, char const *argv[])
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
index ca900ca6e885..f4987dba90bc 100644
--- a/tools/lldb-mi/MIDriverMgr.cpp
+++ b/tools/lldb-mi/MIDriverMgr.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -28,7 +16,6 @@
#include "MICmnLog.h"
#include "MICmnLogMediumFile.h"
#include "MIDriver.h"
-#include "MIUtilTermios.h"
#include "MICmnStreamStdout.h"
#include "MIUtilSingletonHelper.h"
@@ -82,11 +69,6 @@ CMIDriverMgr::Initialize(void)
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)
@@ -116,38 +98,11 @@ CMIDriverMgr::Shutdown(void)
// if( --m_clientUsageRefCnt > 0 )
// return MIstatus::success;
- bool vbAppExitOk = true;
-
ClrErrorDescription();
if (!m_bInitialized)
return MIstatus::success;
- if (vbAppExitOk)
- {
-#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
- {
- 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;
@@ -155,7 +110,6 @@ CMIDriverMgr::Shutdown(void)
// Tidy up
UnregisterDriverAll();
- MIUtilTermios::StdinTermiosReset();
// Note shutdown order is important here
MI::ModuleShutdown<CMICmnResources>(IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg);
@@ -355,26 +309,6 @@ CMIDriverMgr::DriverMainLoop(void)
}
//++ ------------------------------------------------------------------------------------
-// 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
@@ -403,7 +337,7 @@ CMIDriverMgr::DriverParseArgs(const int argc, const char *argv[], FILE *vpStdOut
if (!bOk)
{
CMIUtilString errMsg;
- const MIchar *pErrorCstr = error.GetCString();
+ const char *pErrorCstr = error.GetCString();
if (pErrorCstr != nullptr)
errMsg = CMIUtilString::Format(MIRSRC(IDS_DRIVER_ERR_PARSE_ARGS), m_pDriverCurrent->GetName().c_str(), pErrorCstr);
else
@@ -493,6 +427,7 @@ CMIDriverMgr::DriverGetTheDebugger(void)
// --versionLong
// --log
// --executable
+// --log-dir
// 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
@@ -501,8 +436,9 @@ CMIDriverMgr::DriverGetTheDebugger(void)
// 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.
+// debug session. Using --interpreter on the command line does not action additional
+// commands to initialise a debug session and so be able to launch the process. The directory
+// where the log file is created is specified using --log-dir.
// 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.
@@ -549,13 +485,11 @@ CMIDriverMgr::ParseArgs(const int argc, const char *argv[], bool &vwbExiting)
bool bHaveArgVersion = false;
bool bHaveArgVersionLong = false;
bool bHaveArgLog = false;
+ bool bHaveArgLogDir = false;
bool bHaveArgHelp = false;
+ CMIUtilString strLogDir;
-// 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
@@ -582,6 +516,11 @@ CMIDriverMgr::ParseArgs(const int argc, const char *argv[], bool &vwbExiting)
{
bHaveArgLog = true;
}
+ if (0 == strArg.compare(0,10,"--log-dir="))
+ {
+ strLogDir = strArg.substr(10, CMIUtilString::npos);
+ bHaveArgLogDir = true;
+ }
if ((0 == strArg.compare("--help")) || (0 == strArg.compare("-h")))
{
bHaveArgHelp = true;
@@ -594,7 +533,12 @@ CMIDriverMgr::ParseArgs(const int argc, const char *argv[], bool &vwbExiting)
CMICmnLog::Instance().SetEnabled(true);
}
- // Todo: Remove this output when MI is finished. It is temporary to persuade Ecllipse plugin to work.
+ if (bHaveArgLogDir)
+ {
+ bOk = bOk && CMICmnLogMediumFile::Instance().SetDirectory(strLogDir);
+ }
+
+ // Todo: Remove this output when MI is finished. It is temporary to persuade Eclipse 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)
@@ -604,7 +548,7 @@ CMIDriverMgr::ParseArgs(const int argc, const char *argv[], bool &vwbExiting)
return bOk;
}
- // Todo: Make this the --version when the the above --version version is removed
+ // Todo: Make this the --version when the above --version version is removed
// Handle --versionlong option (ignore the --interpreter option if present)
if (bHaveArgVersionLong)
{
@@ -613,7 +557,7 @@ CMIDriverMgr::ParseArgs(const int argc, const char *argv[], bool &vwbExiting)
return bOk;
}
- // Both '--help' and '--intepreter' means give help for MI only. Without
+ // Both '--help' and '--interpreter' means give help for MI only. Without
// '--interpreter' help the LLDB driver is working and so help is for that.
if (bHaveArgHelp && bHaveArgInterpret)
{
@@ -623,7 +567,7 @@ CMIDriverMgr::ParseArgs(const int argc, const char *argv[], bool &vwbExiting)
}
// This makes the assumption that there is at least one MI compatible
- // driver registered and one LLDB driver registerd and the CMIDriver
+ // driver registered and one LLDB driver registered 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.
@@ -682,8 +626,10 @@ CMIDriverMgr::GetHelpOnCmdLineArgOptions(void) const
MIRSRC(IDE_MI_APP_ARG_VERSION),
MIRSRC(IDE_MI_APP_ARG_VERSION_LONG),
MIRSRC(IDE_MI_APP_ARG_INTERPRETER),
+ MIRSRC(IDE_MI_APP_ARG_SOURCE),
MIRSRC(IDE_MI_APP_ARG_EXECUTEABLE),
CMIUtilString::Format(MIRSRC(IDE_MI_APP_ARG_APP_LOG), CMICmnLogMediumFile::Instance().GetFileName().c_str()),
+ MIRSRC(IDE_MI_APP_ARG_APP_LOG_DIR),
MIRSRC(IDE_MI_APP_ARG_EXECUTABLE),
MIRSRC(IDS_CMD_QUIT_HELP),
MIRSRC(IDE_MI_APP_ARG_EXAMPLE)};
@@ -778,3 +724,19 @@ CMIDriverMgr::GetDriver(const CMIUtilString &vrDriverId) const
return pDriver;
}
+
+
+//++ ------------------------------------------------------------------------------------
+// Details: Gets called when lldb-mi gets a signal. Passed signal to current driver.
+//
+// Type: Method.
+// Args: signal that was delivered
+// Return: None.
+// Throws: None.
+//--
+void
+CMIDriverMgr::DeliverSignal(int signal)
+{
+ if (m_pDriverCurrent != nullptr)
+ m_pDriverCurrent->DeliverSignal(signal);
+}
diff --git a/tools/lldb-mi/MIDriverMgr.h b/tools/lldb-mi/MIDriverMgr.h
index 9e1e121405cb..53fc984f3178 100644
--- a/tools/lldb-mi/MIDriverMgr.h
+++ b/tools/lldb-mi/MIDriverMgr.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -71,7 +59,6 @@ class CMIDriverMgr : public CMICmnBase, public MI::ISingleton<CMIDriverMgr>
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;
@@ -79,6 +66,7 @@ class CMIDriverMgr : public CMICmnBase, public MI::ISingleton<CMIDriverMgr>
virtual bool GetDriverIsGDBMICompatibleDriver(void) const = 0;
virtual bool SetId(const CMIUtilString &vId) = 0;
virtual const CMIUtilString &GetId(void) const = 0;
+ virtual void DeliverSignal(int signal) = 0;
// Not part of the interface, ignore
/* dtor */ virtual ~IDriver(void) {}
@@ -101,11 +89,11 @@ class CMIDriverMgr : public CMICmnBase, public MI::ISingleton<CMIDriverMgr>
//
// 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);
+ void DeliverSignal(int signal);
// Typedef:
private:
diff --git a/tools/lldb-mi/MIExtensions.txt b/tools/lldb-mi/MIExtensions.txt
new file mode 100644
index 000000000000..966cb2f074c9
--- /dev/null
+++ b/tools/lldb-mi/MIExtensions.txt
@@ -0,0 +1,103 @@
+# -file-exec-and-symbols now takes two new (optional) options:
+
+Synopsis
+
+ -file-exec-and-symbols <file> [-p <platform>] [-r <remote-file>]
+
+Specify the executable file to be debugged. This file is the one from which the symbol table is also read.
+When debugging remote targets specify a remote-file for execution and a file from which symbols are read.
+The optional platform is the name of the platform, e.g., "remote-ios" or "ios-simulator". The remote-file
+is the on-device path to the exe.
+
+# -data-info-line
+
+Synopsis
+
+ -data-info-line *<address>
+ -data-info-line <file>:<line>
+
+Provides information about a source line. The input can be <address> like 0x12345678 or <file>:<line>
+where file is a name of source file and line is the line number. As a result the command returns the following
+fields:
+ start - address of the first instruction which refers to that source line
+ end - address of the last instruction which refers to that source line
+ file - the file name
+ line - the line number
+The last two fields are useful in case you have specified a source line using its address.
+
+Example:
+ -data-info-line *0x100000f80
+ ^done,start="0x0000000100000f80",end="0x0000000100000f94",file="/Users/IliaK/p/hello.cpp",line="15"
+
+ -data-info-line hello.cpp:15
+ ^done,start="0x0000000100000f80",end="0x0000000100000f94",file="/Users/IliaK/p/hello.cpp",line="15"
+
+# -data-read-memory-bytes
+
+Synopsis
+
+ -data-read-memory-bytes [--thread <thread-id>] [--frame <frame-index>] [-o <byte-offset>] <address> <count>
+
+Where:
+
+ `address`
+ An expression specifying the start of the memory range to read.
+ `count`
+ Number of bytes to read.
+ `byte-offset`
+ Relative offset in bytes from `address` where reading should start.
+ `thread-id`
+ Integer identifier of the thread within which the expression should be evaluated,
+ if this option is omitted the currently selected thread will be used.
+ This option is not in the MI specification but is implemented by GDB.
+ `frame-index`
+ Index of the frame within which the expression should be evaluated,
+ if this option is omitted the currently selected frame will be used.
+ This option is not in the MI specification but is implemented by GDB.
+
+Reads a block of memory from the specified range.
+
+Note that currently this command works in an all-or-nothing fashion where it either reads the entire
+block of memory successfully and returns it as a single block, or it returns an error. This doesn't
+quite match up with the MI specification that says that subsets of the specified range may be
+returned as individual blocks if only some of the memory within the specified range is accessible.
+
+The result record for this command may contain one or more tuples representing the blocks of memory
+that were read, where each tuple has the following fields:
+
+ `begin`
+ The start of the address range for this block (in hex notation).
+ `end`
+ The end of the address range for this block (in hex notation).
+ `offset`
+ Offset of this block from `address` (that was passed in as an argument).
+ `contents`
+ The actual data in this block (in hex notation).
+
+Example:
+
+ (gdb)
+ -data-read-memory-bytes &array 4
+ ^done,memory=[{begin="0x00007fffffffeccc",offset="0x0000000000000000",end="0x00007fffffffecd0",contents="01020304"}]
+ (gdb)
+
+# =library-loaded notification
+
+The =library-loaded notification has 3 extra fields:
+ symbols-loaded - indicates that there are symbols for the loaded library
+ symbols-path - if symbols are exist then it contains a path for symbols of the loaded library
+ loaded_addr - contains an address of the loaded library or "-" if address isn't resolved yet
+
+For example:
+ =library-loaded,id="/Users/IliaK/p/hello",target-name="/Users/IliaK/p/hello",host-name="/Users/IliaK/p/hello",symbols-loaded="1",symbols-path="/Users/IliaK/p/hello.dSYM/Contents/Resources/DWARF/hello",loaded_addr="-"
+ =library-loaded,id="/usr/lib/dyld",target-name="/usr/lib/dyld",host-name="/usr/lib/dyld",symbols-loaded="0",loaded_addr="0x00007fff5fc00000"
+
+# -target-attach
+
+Synopsis
+
+Additional syntax provided by lldb-mi:
+ -target-attach -n <executable-name> [--waitfor]
+
+Attach to an executable. Using -n allows specifying an executable name to attach to.
+Using this with --watifor can do a deffered attach. The flags -n and --waitfor match the syntax of lldb proper's 'process attach' command.
diff --git a/tools/lldb-mi/MIReadMe.txt b/tools/lldb-mi/MIReadMe.txt
index 47d28e395ede..bc3d4a8d5e5c 100644
--- a/tools/lldb-mi/MIReadMe.txt
+++ b/tools/lldb-mi/MIReadMe.txt
@@ -1,261 +1,37 @@
========================================================================
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/.
+A blog about the MI Driver is available on CodePlay's website. ALthough it may not be
+completely accurate after the recent changes in lldb-mi.
+http://www.codeplay.com/portal/lldb-mi-driver---part-1-introduction
-The MI Driver produces a MILog.txt file which records the actions of the MI
-Driver when in the MI mode only.
+In MI mode and invoked with --log option, lldb-mi generates lldb-mi-log.txt
+This file keeps a history of the MI Driver's activity for one session. It is
+used to aid the debugging of the MI Driver. It also gives warnings about
+command's which do not support certain argument or options.
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.
+registered in the MI Driver's Command Factory will be rejected and an error messsage
+will be generated.
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.
+File MIDriverMain.cpp contains the executables main() function.
=========================================================================
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
+1. Not all commands and their options have been implemented. Please see
+the source code for details.
+2. LLDB-MI may have additinal arguments not used in GDB MI. Please see
+MIExtesnsions.txt
=========================================================================
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)
-
-
+MICmnConfig.h defines various preprocessor build options.
diff --git a/tools/lldb-mi/MIUtilDateTimeStd.cpp b/tools/lldb-mi/MIUtilDateTimeStd.cpp
index bb9e238843e0..995441fb4dec 100644
--- a/tools/lldb-mi/MIUtilDateTimeStd.cpp
+++ b/tools/lldb-mi/MIUtilDateTimeStd.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
@@ -83,3 +71,21 @@ CMIUtilDateTimeStd::GetTime(void)
return strTime;
}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve system local current date and time in yyyy-MM-dd--HH-mm-ss format for log file names.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Text description.
+// Throws: None.
+//--
+CMIUtilString
+CMIUtilDateTimeStd::GetDateTimeLogFilename(void)
+{
+ std::time(&m_rawTime);
+ const std::tm *pTi = std::localtime(&m_rawTime);
+ const CMIUtilString strTime(CMIUtilString::Format("%d%02d%02d%02d%02d%02d", pTi->tm_year + 1900, pTi->tm_mon,
+ pTi->tm_mday, pTi->tm_hour, pTi->tm_min, pTi->tm_sec));
+
+ return strTime;
+}
diff --git a/tools/lldb-mi/MIUtilDateTimeStd.h b/tools/lldb-mi/MIUtilDateTimeStd.h
index 1d9a1dac7dc6..4bc5e5815959 100644
--- a/tools/lldb-mi/MIUtilDateTimeStd.h
+++ b/tools/lldb-mi/MIUtilDateTimeStd.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
@@ -42,6 +30,7 @@ class CMIUtilDateTimeStd
CMIUtilString GetDate(void);
CMIUtilString GetTime(void);
+ CMIUtilString GetDateTimeLogFilename(void);
// Overrideable:
public:
@@ -51,5 +40,5 @@ class CMIUtilDateTimeStd
// Attributes:
private:
std::time_t m_rawTime;
- MIchar m_pScratch[16];
+ char m_pScratch[16];
};
diff --git a/tools/lldb-mi/MIUtilDebug.cpp b/tools/lldb-mi/MIUtilDebug.cpp
index c78506221b44..f7d461bfcd28 100644
--- a/tools/lldb-mi/MIUtilDebug.cpp
+++ b/tools/lldb-mi/MIUtilDebug.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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>
diff --git a/tools/lldb-mi/MIUtilDebug.h b/tools/lldb-mi/MIUtilDebug.h
index d643f73ba97e..b309c5dc2871 100644
--- a/tools/lldb-mi/MIUtilDebug.h
+++ b/tools/lldb-mi/MIUtilDebug.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
diff --git a/tools/lldb-mi/MIUtilFileStd.cpp b/tools/lldb-mi/MIUtilFileStd.cpp
index dc5ea6cb32ff..a0fce65880c6 100644
--- a/tools/lldb-mi/MIUtilFileStd.cpp
+++ b/tools/lldb-mi/MIUtilFileStd.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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>
@@ -159,7 +147,7 @@ CMIUtilFileStd::Write(const CMIUtilString &vData)
// Throws: None.
//--
bool
-CMIUtilFileStd::Write(const MIchar *vpData, const MIuint vCharCnt)
+CMIUtilFileStd::Write(const char *vpData, const MIuint vCharCnt)
{
if (vCharCnt == 0)
return MIstatus::success;
@@ -266,11 +254,11 @@ CMIUtilFileStd::GetLineReturn(void) const
// Throws: None.
//--
CMIUtilString
-CMIUtilFileStd::StripOffFileName(const CMIUtilString &vDirectoryPath) const
+CMIUtilFileStd::StripOffFileName(const CMIUtilString &vDirectoryPath)
{
- const MIint nPos = vDirectoryPath.rfind('\\');
- MIint nPos2 = vDirectoryPath.rfind('/');
- if ((nPos == (MIint)std::string::npos) && (nPos2 == (MIint)std::string::npos))
+ const size_t nPos = vDirectoryPath.rfind('\\');
+ size_t nPos2 = vDirectoryPath.rfind('/');
+ if ((nPos == std::string::npos) && (nPos2 == std::string::npos))
return vDirectoryPath;
if (nPos > nPos2)
@@ -281,14 +269,14 @@ CMIUtilFileStd::StripOffFileName(const CMIUtilString &vDirectoryPath) const
}
//++ ------------------------------------------------------------------------------------
-// Details: Return either backslash or forward slash appropriate to the OS this applilcation
+// Details: Return either backslash or forward slash appropriate to the OS this application
// is running on.
// Type: Static method.
// Args: None.
-// Return: MIchar - '/' or '\' character.
+// Return: char - '/' or '\' character.
// Throws: None.
//--
-MIchar
+char
CMIUtilFileStd::GetSlash(void)
{
#if !defined(_MSC_VER)
diff --git a/tools/lldb-mi/MIUtilFileStd.h b/tools/lldb-mi/MIUtilFileStd.h
index 29537771265e..4b27d2f2faeb 100644
--- a/tools/lldb-mi/MIUtilFileStd.h
+++ b/tools/lldb-mi/MIUtilFileStd.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
@@ -35,7 +23,7 @@ class CMIUtilFileStd : public CMICmnBase
{
// Static:
public:
- static MIchar GetSlash(void);
+ static char GetSlash(void);
// Methods:
public:
@@ -43,12 +31,12 @@ class CMIUtilFileStd : public CMICmnBase
//
bool CreateWrite(const CMIUtilString &vFileNamePath, bool &vwrbNewCreated);
bool Write(const CMIUtilString &vData);
- bool Write(const MIchar *vpData, const MIuint vCharCnt);
+ bool Write(const char *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;
+ static CMIUtilString StripOffFileName(const CMIUtilString &vDirectoryPath);
// Overridden:
public:
diff --git a/tools/lldb-mi/MIUtilMapIdToVariant.cpp b/tools/lldb-mi/MIUtilMapIdToVariant.cpp
index 413677268bed..debac2081b8b 100644
--- a/tools/lldb-mi/MIUtilMapIdToVariant.cpp
+++ b/tools/lldb-mi/MIUtilMapIdToVariant.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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"
diff --git a/tools/lldb-mi/MIUtilMapIdToVariant.h b/tools/lldb-mi/MIUtilMapIdToVariant.h
index 6a7765d6022c..1b9c6a102ef0 100644
--- a/tools/lldb-mi/MIUtilMapIdToVariant.h
+++ b/tools/lldb-mi/MIUtilMapIdToVariant.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MIUtilSingletonBase.h b/tools/lldb-mi/MIUtilSingletonBase.h
index 44ad6cd9972c..c6d7f55b159c 100644
--- a/tools/lldb-mi/MIUtilSingletonBase.h
+++ b/tools/lldb-mi/MIUtilSingletonBase.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
diff --git a/tools/lldb-mi/MIUtilSingletonHelper.h b/tools/lldb-mi/MIUtilSingletonHelper.h
index a06a74296d03..5bd879e1aa9f 100644
--- a/tools/lldb-mi/MIUtilSingletonHelper.h
+++ b/tools/lldb-mi/MIUtilSingletonHelper.h
@@ -6,18 +6,6 @@
// 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.
//--
diff --git a/tools/lldb-mi/MIUtilString.cpp b/tools/lldb-mi/MIUtilString.cpp
index 0464eadccbff..fc7717749da8 100644
--- a/tools/lldb-mi/MIUtilString.cpp
+++ b/tools/lldb-mi/MIUtilString.cpp
@@ -7,24 +7,13 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
+#include <inttypes.h> // for PRIx8
+#include <limits.h> // for ULONG_MAX
+#include <memory> // std::unique_ptr
+#include <sstream> // std::stringstream
+#include <stdarg.h> // va_list, va_start, var_end
+#include <string.h> // for strncmp
// In-house headers:
#include "MIUtilString.h"
@@ -48,7 +37,7 @@ CMIUtilString::CMIUtilString(void)
// Return: None.
// Throws: None.
//--
-CMIUtilString::CMIUtilString(const MIchar *vpData)
+CMIUtilString::CMIUtilString(const char *vpData)
: std::string(vpData)
{
}
@@ -60,19 +49,19 @@ CMIUtilString::CMIUtilString(const MIchar *vpData)
// Return: None.
// Throws: None.
//--
-CMIUtilString::CMIUtilString(const MIchar *const *vpData)
+CMIUtilString::CMIUtilString(const char *const *vpData)
: std::string((const char *)vpData)
{
}
//++ ------------------------------------------------------------------------------------
-// Details: CMIUtilString assigment operator.
+// Details: CMIUtilString assignment operator.
// Type: Method.
// Args: vpRhs - Pointer to UTF8 text data.
// Return: CMIUtilString & - *this string.
// Throws: None.
//--
-CMIUtilString &CMIUtilString::operator=(const MIchar *vpRhs)
+CMIUtilString &CMIUtilString::operator=(const char *vpRhs)
{
if (*this == vpRhs)
return *this;
@@ -86,7 +75,7 @@ CMIUtilString &CMIUtilString::operator=(const MIchar *vpRhs)
}
//++ ------------------------------------------------------------------------------------
-// Details: CMIUtilString assigment operator.
+// Details: CMIUtilString assignment operator.
// Type: Method.
// Args: vrRhs - The other string to copy from.
// Return: CMIUtilString & - *this string.
@@ -213,10 +202,10 @@ CMIUtilString::FormatValist(const CMIUtilString &vrFormating, va_list vArgs)
// 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.
+// Return: size_t - Number of splits found in the string data.
// Throws: None.
//--
-MIuint
+size_t
CMIUtilString::Split(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits) const
{
vwVecSplits.clear();
@@ -224,40 +213,30 @@ CMIUtilString::Split(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits)
if (this->empty() || vDelimiter.empty())
return 0;
- MIint nPos = find(vDelimiter);
- if (nPos == (MIint)std::string::npos)
+ const size_t nLen(length());
+ size_t nOffset(0);
+ do
{
- vwVecSplits.push_back(*this);
- return 1;
- }
- const MIint strLen(length());
- if (nPos == strLen)
- {
- vwVecSplits.push_back(*this);
- return 1;
- }
+ // Find first occurrence which doesn't match to the delimiter
+ const size_t nSectionPos(FindFirstNot(vDelimiter, nOffset));
+ if (nSectionPos == std::string::npos)
+ break;
- 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))
+ // Find next occurrence of the delimiter after section
+ size_t nNextDelimiterPos(FindFirst(vDelimiter, nSectionPos));
+ if (nNextDelimiterPos == std::string::npos)
+ nNextDelimiterPos = nLen;
+
+ // Extract string between delimiters
+ const size_t nSectionLen(nNextDelimiterPos - nSectionPos);
+ const std::string strSection(substr(nSectionPos, nSectionLen));
vwVecSplits.push_back(strSection.c_str());
+ // Next
+ nOffset = nNextDelimiterPos + 1;
+ }
+ while (nOffset < nLen);
+
return vwVecSplits.size();
}
@@ -265,17 +244,17 @@ CMIUtilString::Split(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits)
// 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
+// then they are not added to the list of splits. Quotes that are embedded in
// 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.
+// Return: size_t - Number of splits found in the string data.
// Throws: None.
//--
-MIuint
+size_t
CMIUtilString::SplitConsiderQuotes(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits) const
{
vwVecSplits.clear();
@@ -283,85 +262,54 @@ CMIUtilString::SplitConsiderQuotes(const CMIUtilString &vDelimiter, VecString_t
if (this->empty() || vDelimiter.empty())
return 0;
- MIint nPos = find(vDelimiter);
- if (nPos == (MIint)std::string::npos)
+ const size_t nLen(length());
+ size_t nOffset(0);
+ do
{
- vwVecSplits.push_back(*this);
- return 1;
- }
- const MIint strLen(length());
- if (nPos == strLen)
- {
- vwVecSplits.push_back(*this);
- return 1;
- }
+ // Find first occurrence which doesn't match to the delimiter
+ const size_t nSectionPos(FindFirstNot(vDelimiter, nOffset));
+ if (nSectionPos == std::string::npos)
+ break;
- // 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)
+ // Find next occurrence of the delimiter after (quoted) section
+ const bool bSkipQuotedText(true);
+ bool bUnmatchedQuote(false);
+ size_t nNextDelimiterPos(FindFirst(vDelimiter, bSkipQuotedText, bUnmatchedQuote, nSectionPos));
+ if (bUnmatchedQuote)
{
- nPosQ2 = find(cQuote, nPosQ2);
- if ((nPosQ2 == (MIint)std::string::npos) || (at(nPosQ2 - 1) != cBckSlash))
- break;
- nPosQ2++;
+ vwVecSplits.clear();
+ return 0;
}
- bHaveQuotes = (nPosQ2 != (MIint)std::string::npos);
- }
+ if (nNextDelimiterPos == std::string::npos)
+ nNextDelimiterPos = nLen;
- 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))
+ // Extract string between delimiters
+ const size_t nSectionLen(nNextDelimiterPos - nSectionPos);
+ const std::string strSection(substr(nSectionPos, nSectionLen));
vwVecSplits.push_back(strSection.c_str());
+ // Next
+ nOffset = nNextDelimiterPos + 1;
+ }
+ while (nOffset < nLen);
+
return vwVecSplits.size();
}
//++ ------------------------------------------------------------------------------------
+// Details: Split string into lines using \n and return an array of strings.
+// Type: Method.
+// Args: vwVecSplits - (W) Container of splits found in string data.
+// Return: size_t - Number of splits found in the string data.
+// Throws: None.
+//--
+size_t
+CMIUtilString::SplitLines(VecString_t &vwVecSplits) const
+{
+ return Split("\n", vwVecSplits);
+}
+
+//++ ------------------------------------------------------------------------------------
// Details: Remove '\n' from the end of string if found. It does not alter
// *this string.
// Type: Method.
@@ -372,8 +320,8 @@ CMIUtilString::SplitConsiderQuotes(const CMIUtilString &vDelimiter, VecString_t
CMIUtilString
CMIUtilString::StripCREndOfLine(void) const
{
- const MIint nPos = rfind('\n');
- if (nPos == (MIint)std::string::npos)
+ const size_t nPos = rfind('\n');
+ if (nPos == std::string::npos)
return *this;
const CMIUtilString strNew(substr(0, nPos).c_str());
@@ -410,12 +358,12 @@ CMIUtilString::FindAndReplace(const CMIUtilString &vFind, const CMIUtilString &v
if (vFind.empty() || this->empty())
return *this;
- MIint nPos = find(vFind);
- if (nPos == (MIint)std::string::npos)
+ size_t nPos = find(vFind);
+ if (nPos == std::string::npos)
return *this;
CMIUtilString strNew(*this);
- while (nPos != (MIint)std::string::npos)
+ while (nPos != std::string::npos)
{
strNew.replace(nPos, vFind.length(), vReplaceWith);
nPos += vReplaceWith.length();
@@ -441,8 +389,30 @@ CMIUtilString::IsNumber(void) const
if ((at(0) == '-') && (length() == 1))
return false;
- const MIint nPos = find_first_not_of("-.0123456789");
- if (nPos != (MIint)std::string::npos)
+ const size_t nPos = find_first_not_of("-.0123456789");
+ if (nPos != std::string::npos)
+ return false;
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check if *this string is a hexadecimal number.
+// Type: Method.
+// Args: None.
+// Return: bool - True = yes number, false not a number.
+// Throws: None.
+//--
+bool
+CMIUtilString::IsHexadecimalNumber(void) const
+{
+ // Compare '0x..' prefix
+ if ((strncmp(c_str(), "0x", 2) != 0) && (strncmp(c_str(), "0X", 2) != 0))
+ return false;
+
+ // Skip '0x..' prefix
+ const size_t nPos = find_first_not_of("01234567890ABCDEFabcedf", 2);
+ if (nPos != std::string::npos)
return false;
return true;
@@ -452,7 +422,7 @@ CMIUtilString::IsNumber(void) const
// 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.
+// Args: vwrNumber - (W) Number extracted from the string.
// Return: bool - True = yes number, false not a number.
// Throws: None.
//--
@@ -478,7 +448,7 @@ CMIUtilString::ExtractNumber(MIint64 &vwrNumber) const
//++ ------------------------------------------------------------------------------------
// Details: Extract the number from the hexadecimal string..
// Type: Method.
-// Args: vwrNumber - (W) Number exracted from the string.
+// Args: vwrNumber - (W) Number extracted from the string.
// Return: bool - True = yes number, false not a number.
// Throws: None.
//--
@@ -487,16 +457,16 @@ CMIUtilString::ExtractNumberFromHexadecimal(MIint64 &vwrNumber) const
{
vwrNumber = 0;
- const MIint nPos = find_first_not_of("x01234567890ABCDEFabcedf");
- if (nPos != (MIint)std::string::npos)
+ const size_t nPos = find_first_not_of("xX01234567890ABCDEFabcedf");
+ if (nPos != std::string::npos)
return false;
- const MIint64 nNum = ::strtoul(this->c_str(), nullptr, 16);
- if (nNum != LONG_MAX)
- {
- vwrNumber = nNum;
- return true;
- }
+ errno = 0;
+ const MIuint64 nNum = ::strtoull(this->c_str(), nullptr, 16);
+ if (errno == ERANGE)
+ return false;
+
+ vwrNumber = static_cast<MIint64>(nNum);
return true;
}
@@ -505,21 +475,20 @@ CMIUtilString::ExtractNumberFromHexadecimal(MIint64 &vwrNumber) const
// 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.
+// Args: vpText - (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)
+CMIUtilString::IsAllValidAlphaAndNumeric(const char *vpText)
{
- const MIuint len = ::strlen(&vrText);
+ const size_t len = ::strlen(vpText);
if (len == 0)
return false;
- MIchar *pPtr = const_cast<MIchar *>(&vrText);
- for (MIuint i = 0; i < len; i++, pPtr++)
+ for (size_t i = 0; i < len; i++, vpText++)
{
- const MIchar c = *pPtr;
+ const char c = *vpText;
if (::isalnum((int)c) == 0)
return false;
}
@@ -556,14 +525,14 @@ 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)
+ const char *pWhiteSpace = " \t\n\v\f\r";
+ const size_t nPos = find_last_not_of(pWhiteSpace);
+ if (nPos != 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)
+ const size_t nPos2 = strNew.find_first_not_of(pWhiteSpace);
+ if (nPos2 != std::string::npos)
{
strNew = strNew.substr(nPos2).c_str();
}
@@ -579,10 +548,10 @@ CMIUtilString::Trim(void) const
// Throws: None.
//--
CMIUtilString
-CMIUtilString::Trim(const MIchar vChar) const
+CMIUtilString::Trim(const char vChar) const
{
CMIUtilString strNew(*this);
- const MIint nLen = strNew.length();
+ const size_t nLen = strNew.length();
if (nLen > 1)
{
if ((strNew[0] == vChar) && (strNew[nLen - 1] == vChar))
@@ -615,7 +584,7 @@ CMIUtilString::FormatBinary(const MIuint64 vnDecimal)
nNum = nNum >> 1;
nLen++;
}
- MIchar pN[nConstBits + 1];
+ char pN[nConstBits + 1];
MIuint j = 0;
for (i = nLen; i > 0; --i, j++)
{
@@ -637,7 +606,7 @@ CMIUtilString::FormatBinary(const MIuint64 vnDecimal)
// Throws: None.
//--
CMIUtilString
-CMIUtilString::RemoveRepeatedCharacters(const MIchar vChar)
+CMIUtilString::RemoveRepeatedCharacters(const char vChar)
{
return RemoveRepeatedCharacters(0, vChar);
}
@@ -648,22 +617,22 @@ CMIUtilString::RemoveRepeatedCharacters(const MIchar vChar)
// character.
// Type: Method.
// Args: vChar - (R) The character to search for and remove adjacent duplicates.
-// vnPos - (R) Character position in the string.
+// vnPos - Character position in the string.
// Return: CMIUtilString - New version of the string.
// Throws: None.
//--
CMIUtilString
-CMIUtilString::RemoveRepeatedCharacters(const MIint vnPos, const MIchar vChar)
+CMIUtilString::RemoveRepeatedCharacters(size_t vnPos, const char vChar)
{
- const MIchar cQuote = '"';
+ const char cQuote = '"';
// Look for first quote of two
- MIint nPos = find(cQuote, vnPos);
- if (nPos == (MIint)std::string::npos)
+ const size_t nPos = find(cQuote, vnPos);
+ if (nPos == std::string::npos)
return *this;
- const MIint nPosNext = nPos + 1;
- if (nPosNext > (MIint)length())
+ const size_t nPosNext = nPos + 1;
+ if (nPosNext > length())
return *this;
if (at(nPosNext) == cQuote)
@@ -685,14 +654,296 @@ CMIUtilString::RemoveRepeatedCharacters(const MIint vnPos, const MIchar vChar)
bool
CMIUtilString::IsQuoted(void) const
{
- const MIchar cQuote = '"';
+ const char cQuote = '"';
if (at(0) != cQuote)
return false;
- const MIint nLen = length();
+ const size_t nLen = length();
if ((nLen > 0) && (at(nLen - 1) != cQuote))
return false;
return true;
}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Find first occurrence in *this string which matches the pattern.
+// Type: Method.
+// Args: vrPattern - (R) The pattern to search for.
+// vnPos - The starting position at which to start searching. (Dflt = 0)
+// Return: size_t - The position of the first substring that match.
+// Throws: None.
+//--
+size_t
+CMIUtilString::FindFirst(const CMIUtilString &vrPattern, size_t vnPos /* = 0 */) const
+{
+ return find(vrPattern, vnPos);
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Find first occurrence in *this string which matches the pattern and isn't surrounded by quotes.
+// Type: Method.
+// Args: vrPattern - (R) The pattern to search for.
+// vbSkipQuotedText - (R) True = don't look at quoted text, false = otherwise.
+// vrwbNotFoundClosedQuote - (W) True = parsing error: unmatched quote, false = otherwise.
+// vnPos - Position of the first character in the string to be considered in the search. (Dflt = 0)
+// Return: size_t - The position of the first substring that matches and isn't quoted.
+// Throws: None.
+//--
+size_t
+CMIUtilString::FindFirst(const CMIUtilString &vrPattern, const bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote,
+ size_t vnPos /* = 0 */) const
+{
+ vrwbNotFoundClosedQuote = false;
+
+ if (!vbSkipQuotedText)
+ return FindFirst(vrPattern, vnPos);
+
+ const size_t nLen(length());
+
+ size_t nPos = vnPos;
+ do
+ {
+ const size_t nQuotePos(FindFirstQuote(nPos));
+ const size_t nPatternPos(FindFirst(vrPattern, nPos));
+ if (nQuotePos == std::string::npos)
+ return nPatternPos;
+
+ const size_t nQuoteClosedPos = FindFirstQuote(nQuotePos + 1);
+ if (nQuoteClosedPos == std::string::npos)
+ {
+ vrwbNotFoundClosedQuote = true;
+ return std::string::npos;
+ }
+
+ if ((nPatternPos == std::string::npos) || (nPatternPos < nQuotePos))
+ return nPatternPos;
+
+ nPos = nQuoteClosedPos + 1;
+ }
+ while (nPos < nLen);
+
+ return std::string::npos;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Find first occurrence in *this string which doesn't match the pattern.
+// Type: Method.
+// Args: vrPattern - (R) The pattern to search for.
+// vnPos - Position of the first character in the string to be considered in the search. (Dflt = 0)
+// Return: size_t - The position of the first character that doesn't match.
+// Throws: None.
+//--
+size_t
+CMIUtilString::FindFirstNot(const CMIUtilString &vrPattern, size_t vnPos /* = 0 */) const
+{
+ const size_t nLen(length());
+ const size_t nPatternLen(vrPattern.length());
+
+ size_t nPatternPos(vnPos);
+ do
+ {
+ const bool bMatchPattern(compare(nPatternPos, nPatternLen, vrPattern) == 0);
+ if (!bMatchPattern)
+ return nPatternPos;
+ nPatternPos += nPatternLen;
+ }
+ while (nPatternPos < nLen);
+
+ return std::string::npos;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Find first occurrence of not escaped quotation mark in *this string.
+// Type: Method.
+// Args: vnPos - Position of the first character in the string to be considered in the search.
+// Return: size_t - The position of the quotation mark.
+// Throws: None.
+//--
+size_t
+CMIUtilString::FindFirstQuote(size_t vnPos) const
+{
+ const char cBckSlash('\\');
+ const char cQuote('"');
+ const size_t nLen(length());
+
+ size_t nPos = vnPos;
+ do
+ {
+ const size_t nBckSlashPos(find(cBckSlash, nPos));
+ const size_t nQuotePos(find(cQuote, nPos));
+ if ((nBckSlashPos == std::string::npos) || (nQuotePos == std::string::npos))
+ return nQuotePos;
+
+ if (nQuotePos < nBckSlashPos)
+ return nQuotePos;
+
+ // Skip 2 characters: First is '\', second is that which is escaped by '\'
+ nPos = nBckSlashPos + 2;
+ }
+ while (nPos < nLen);
+
+ return std::string::npos;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get escaped string from *this string.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - The escaped version of the initial string.
+// Throws: None.
+//--
+CMIUtilString
+CMIUtilString::Escape(bool vbEscapeQuotes /* = false */) const
+{
+ const size_t nLen(length());
+ CMIUtilString strNew;
+ strNew.reserve(nLen);
+ for (size_t nIndex(0); nIndex < nLen; ++nIndex)
+ {
+ const char cUnescapedChar((*this)[nIndex]);
+ if (cUnescapedChar == '"' && vbEscapeQuotes)
+ strNew.append("\\\"");
+ else
+ strNew.append(ConvertToPrintableASCII((char)cUnescapedChar));
+ }
+ return strNew;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get string with backslashes in front of double quote '"' and backslash '\\'
+// characters.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - The wrapped version of the initial string.
+// Throws: None.
+//--
+CMIUtilString
+CMIUtilString::AddSlashes(void) const
+{
+ const char cBckSlash('\\');
+ const size_t nLen(length());
+ CMIUtilString strNew;
+ strNew.reserve(nLen);
+
+ size_t nOffset(0);
+ while (nOffset < nLen)
+ {
+ const size_t nUnescapedCharPos(find_first_of("\"\\", nOffset));
+ const bool bUnescapedCharNotFound(nUnescapedCharPos == std::string::npos);
+ if (bUnescapedCharNotFound)
+ {
+ const size_t nAppendAll(std::string::npos);
+ strNew.append(*this, nOffset, nAppendAll);
+ break;
+ }
+ const size_t nAppendLen(nUnescapedCharPos - nOffset);
+ strNew.append(*this, nOffset, nAppendLen);
+ strNew.push_back(cBckSlash);
+ const char cUnescapedChar((*this)[nUnescapedCharPos]);
+ strNew.push_back(cUnescapedChar);
+ nOffset = nUnescapedCharPos + 1;
+ }
+
+ return strNew;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove backslashes added by CMIUtilString::AddSlashes.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - The initial version of wrapped string.
+// Throws: None.
+//--
+CMIUtilString
+CMIUtilString::StripSlashes(void) const
+{
+ const char cBckSlash('\\');
+ const size_t nLen(length());
+ CMIUtilString strNew;
+ strNew.reserve(nLen);
+
+ size_t nOffset(0);
+ while (nOffset < nLen)
+ {
+ const size_t nBckSlashPos(find(cBckSlash, nOffset));
+ const bool bBckSlashNotFound(nBckSlashPos == std::string::npos);
+ if (bBckSlashNotFound)
+ {
+ const size_t nAppendAll(std::string::npos);
+ strNew.append(*this, nOffset, nAppendAll);
+ break;
+ }
+ const size_t nAppendLen(nBckSlashPos - nOffset);
+ strNew.append(*this, nOffset, nAppendLen);
+ const bool bBckSlashIsLast(nBckSlashPos == nLen);
+ if (bBckSlashIsLast)
+ {
+ strNew.push_back(cBckSlash);
+ break;
+ }
+ const char cEscapedChar((*this)[nBckSlashPos + 1]);
+ const size_t nEscapedCharPos(std::string("\"\\").find(cEscapedChar));
+ const bool bEscapedCharNotFound(nEscapedCharPos == std::string::npos);
+ if (bEscapedCharNotFound)
+ strNew.push_back(cBckSlash);
+ strNew.push_back(cEscapedChar);
+ nOffset = nBckSlashPos + 2;
+ }
+
+ return strNew;
+}
+
+CMIUtilString
+CMIUtilString::ConvertToPrintableASCII(const char vChar)
+{
+ switch (vChar)
+ {
+ case '\a':
+ return "\\a";
+ case '\b':
+ return "\\b";
+ case '\t':
+ return "\\t";
+ case '\n':
+ return "\\n";
+ case '\v':
+ return "\\v";
+ case '\f':
+ return "\\f";
+ case '\r':
+ return "\\r";
+ case '\033':
+ return "\\e";
+ case '\\':
+ return "\\\\";
+ default:
+ if (::isprint(vChar))
+ return Format("%c", vChar);
+ else
+ return Format("\\x%02" PRIx8, vChar);
+ }
+}
+
+CMIUtilString
+CMIUtilString::ConvertToPrintableASCII(const char16_t vChar16)
+{
+ if (vChar16 == (char16_t)(char)vChar16 && ::isprint(vChar16))
+ // Convert char16_t to char (if possible)
+ return Format("%c", vChar16);
+ else
+ return Format("\\u%02" PRIx8 "%02" PRIx8,
+ (vChar16 >> 8) & 0xff, vChar16 & 0xff);
+}
+
+CMIUtilString
+CMIUtilString::ConvertToPrintableASCII(const char32_t vChar32)
+{
+ if (vChar32 == (char32_t)(char)vChar32 && ::isprint(vChar32))
+ // Convert char32_t to char (if possible)
+ return Format("%c", vChar32);
+ else
+ return Format("\\U%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8,
+ (vChar32 >> 24) & 0xff, (vChar32 >> 16) & 0xff,
+ (vChar32 >> 8) & 0xff, vChar32 & 0xff);
+}
diff --git a/tools/lldb-mi/MIUtilString.h b/tools/lldb-mi/MIUtilString.h
index 162dcbf68852..eac0746e7d0d 100644
--- a/tools/lldb-mi/MIUtilString.h
+++ b/tools/lldb-mi/MIUtilString.h
@@ -7,23 +7,12 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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>
+#include <cinttypes>
// In-house headers:
#include "MIDataTypes.h"
@@ -46,28 +35,40 @@ class CMIUtilString : public std::string
static CMIUtilString Format(const CMIUtilString vFormating, ...);
static CMIUtilString FormatBinary(const MIuint64 vnDecimal);
static CMIUtilString FormatValist(const CMIUtilString &vrFormating, va_list vArgs);
- static bool IsAllValidAlphaAndNumeric(const MIchar &vrText);
+ static bool IsAllValidAlphaAndNumeric(const char *vpText);
static bool Compare(const CMIUtilString &vrLhs, const CMIUtilString &vrRhs);
+ static CMIUtilString ConvertToPrintableASCII(const char vChar);
+ static CMIUtilString ConvertToPrintableASCII(const char16_t vChar16);
+ static CMIUtilString ConvertToPrintableASCII(const char32_t vChar32);
// Methods:
public:
/* ctor */ CMIUtilString(void);
- /* ctor */ CMIUtilString(const MIchar *vpData);
- /* ctor */ CMIUtilString(const MIchar *const *vpData);
+ /* ctor */ CMIUtilString(const char *vpData);
+ /* ctor */ CMIUtilString(const char *const *vpData);
//
bool ExtractNumber(MIint64 &vwrNumber) const;
CMIUtilString FindAndReplace(const CMIUtilString &vFind, const CMIUtilString &vReplaceWith) const;
bool IsNumber(void) const;
+ bool IsHexadecimalNumber(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 RemoveRepeatedCharacters(const char vChar);
+ size_t Split(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits) const;
+ size_t SplitConsiderQuotes(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits) const;
+ size_t SplitLines(VecString_t &vwVecSplits) const;
CMIUtilString StripCREndOfLine(void) const;
CMIUtilString StripCRAll(void) const;
CMIUtilString Trim(void) const;
- CMIUtilString Trim(const MIchar vChar) const;
+ CMIUtilString Trim(const char vChar) const;
+ size_t FindFirst(const CMIUtilString &vrPattern, size_t vnPos = 0) const;
+ size_t FindFirst(const CMIUtilString &vrPattern, bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote,
+ size_t vnPos = 0) const;
+ size_t FindFirstNot(const CMIUtilString &vrPattern, size_t vnPos = 0) const;
+ CMIUtilString Escape(bool vbEscapeQuotes = false) const;
+ CMIUtilString AddSlashes(void) const;
+ CMIUtilString StripSlashes(void) const;
//
- CMIUtilString &operator=(const MIchar *vpRhs);
+ CMIUtilString &operator=(const char *vpRhs);
CMIUtilString &operator=(const std::string &vrRhs);
// Overrideable:
@@ -81,5 +82,6 @@ class CMIUtilString : public std::string
// Methods:
private:
bool ExtractNumberFromHexadecimal(MIint64 &vwrNumber) const;
- CMIUtilString RemoveRepeatedCharacters(const MIint vnPos, const MIchar vChar);
+ CMIUtilString RemoveRepeatedCharacters(size_t vnPos, const char vChar);
+ size_t FindFirstQuote(size_t vnPos) const;
};
diff --git a/tools/lldb-mi/MIUtilSystemLinux.cpp b/tools/lldb-mi/MIUtilSystemLinux.cpp
index 8227302356c5..a4ae327657f7 100644
--- a/tools/lldb-mi/MIUtilSystemLinux.cpp
+++ b/tools/lldb-mi/MIUtilSystemLinux.cpp
@@ -7,19 +7,7 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__linux__)
// In-house headers:
#include "MIUtilSystemLinux.h"
diff --git a/tools/lldb-mi/MIUtilSystemLinux.h b/tools/lldb-mi/MIUtilSystemLinux.h
index 451b887e209a..975714bd6f47 100644
--- a/tools/lldb-mi/MIUtilSystemLinux.h
+++ b/tools/lldb-mi/MIUtilSystemLinux.h
@@ -7,21 +7,9 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__linux__)
// In-house headers:
#include "MIUtilString.h"
diff --git a/tools/lldb-mi/MIUtilSystemOsx.cpp b/tools/lldb-mi/MIUtilSystemOsx.cpp
index f095c6212eb4..1834651d40b0 100644
--- a/tools/lldb-mi/MIUtilSystemOsx.cpp
+++ b/tools/lldb-mi/MIUtilSystemOsx.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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:
diff --git a/tools/lldb-mi/MIUtilSystemOsx.h b/tools/lldb-mi/MIUtilSystemOsx.h
index 182b0c950cd7..b30e258626bd 100644
--- a/tools/lldb-mi/MIUtilSystemOsx.h
+++ b/tools/lldb-mi/MIUtilSystemOsx.h
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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__)
diff --git a/tools/lldb-mi/MIUtilSystemWindows.cpp b/tools/lldb-mi/MIUtilSystemWindows.cpp
index f03fa225cd90..19c6e9eb979f 100644
--- a/tools/lldb-mi/MIUtilSystemWindows.cpp
+++ b/tools/lldb-mi/MIUtilSystemWindows.cpp
@@ -7,18 +7,6 @@
//
//===----------------------------------------------------------------------===//
-//++
-// 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
@@ -29,6 +17,7 @@
// In-house headers:
#include "MIUtilSystemWindows.h"
#include "MICmnResources.h"
+#include "MIUtilFileStd.h"
//++ ------------------------------------------------------------------------------------
// Details: CMIUtilSystemWindows constructor.
@@ -122,15 +111,13 @@ 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
+ if (!::GetModuleFileName(hModule, &pPath[0], MAX_PATH))
{
bOk = MIstatus::failure;
- vrwFileNamePath = strLastErr;
+ vrwFileNamePath = GetOSLastError();
}
+ else
+ vrwFileNamePath = &pPath[0];
return bOk;
}
@@ -147,7 +134,8 @@ CMIUtilSystemWindows::GetExecutablesPath(CMIUtilString &vrwFileNamePath) const
bool
CMIUtilSystemWindows::GetLogFilesPath(CMIUtilString &vrwFileNamePath) const
{
- return GetExecutablesPath(vrwFileNamePath);
+ vrwFileNamePath = CMIUtilString(".");
+ return MIstatus::success;
}
#endif // #if defined( _MSC_VER )
diff --git a/tools/lldb-mi/MIUtilSystemWindows.h b/tools/lldb-mi/MIUtilSystemWindows.h
index 59e2de02df53..696c2b286dfc 100644
--- a/tools/lldb-mi/MIUtilSystemWindows.h
+++ b/tools/lldb-mi/MIUtilSystemWindows.h
@@ -6,18 +6,6 @@
// 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)
diff --git a/tools/lldb-mi/MIUtilTermios.cpp b/tools/lldb-mi/MIUtilTermios.cpp
deleted file mode 100644
index fb71a67c8541..000000000000
--- a/tools/lldb-mi/MIUtilTermios.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-//===-- 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
deleted file mode 100644
index f1983d64f005..000000000000
--- a/tools/lldb-mi/MIUtilTermios.h
+++ /dev/null
@@ -1,30 +0,0 @@
-//===-- 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
index 1cf04fa5b2ae..2dc6d3d28dde 100644
--- a/tools/lldb-mi/MIUtilThreadBaseStd.cpp
+++ b/tools/lldb-mi/MIUtilThreadBaseStd.cpp
@@ -6,18 +6,6 @@
// 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.
//--
@@ -217,6 +205,8 @@ CMIUtilThreadActiveObjBase::ThreadManage(void)
// Execute the finish routine just before we die
// to give the object a chance to clean up
ThreadFinish();
+
+ m_thread.Finish();
}
//---------------------------------------------------------------------------------------
@@ -226,6 +216,7 @@ CMIUtilThreadActiveObjBase::ThreadManage(void)
//
CMIUtilThread::CMIUtilThread(void)
: m_pThread(nullptr)
+ , m_bIsActive(false)
{
}
@@ -278,12 +269,24 @@ CMIUtilThread::Join(void)
bool
CMIUtilThread::IsActive(void)
{
- // Lock while we access the thread pointer
+ // Lock while we access the thread status
+ CMIUtilThreadLock _lock(m_mutex);
+ return m_bIsActive;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Finish this thread
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void
+CMIUtilThread::Finish(void)
+{
+ // Lock while we access the thread status
CMIUtilThreadLock _lock(m_mutex);
- if (m_pThread == nullptr)
- return false;
- else
- return true;
+ m_bIsActive = false;
}
//++ ------------------------------------------------------------------------------------
@@ -298,8 +301,12 @@ CMIUtilThread::IsActive(void)
bool
CMIUtilThread::Start(FnThreadProc vpFn, void *vpArg)
{
- // Create the std thread, which starts immediately
+ // Lock while we access the thread pointer and status
+ CMIUtilThreadLock _lock(m_mutex);
+
+ // Create the std thread, which starts immediately and update its status
m_pThread = new std::thread(vpFn, vpArg);
+ m_bIsActive = true;
// We expect to always be able to create one
assert(m_pThread != nullptr);
diff --git a/tools/lldb-mi/MIUtilThreadBaseStd.h b/tools/lldb-mi/MIUtilThreadBaseStd.h
index e3cf5083011d..504d8303de1d 100644
--- a/tools/lldb-mi/MIUtilThreadBaseStd.h
+++ b/tools/lldb-mi/MIUtilThreadBaseStd.h
@@ -6,18 +6,6 @@
// 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.
//--
@@ -87,6 +75,8 @@ class CMIUtilThread
Join(void); // Wait for this thread to stop
bool
IsActive(void); // Returns true if this thread is running
+ void
+ Finish(void); // Finish this thread
// Overrideable:
public:
@@ -96,6 +86,7 @@ class CMIUtilThread
private:
CMIUtilThreadMutex m_mutex;
std::thread *m_pThread;
+ bool m_bIsActive;
};
//++ ============================================================================
diff --git a/tools/lldb-mi/MIUtilVariant.cpp b/tools/lldb-mi/MIUtilVariant.cpp
index fcf1ca8868a9..dff8072aa105 100644
--- a/tools/lldb-mi/MIUtilVariant.cpp
+++ b/tools/lldb-mi/MIUtilVariant.cpp
@@ -6,18 +6,6 @@
// 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.
//--
diff --git a/tools/lldb-mi/MIUtilVariant.h b/tools/lldb-mi/MIUtilVariant.h
index aa1604ab6ff9..8e7ac7b8573a 100644
--- a/tools/lldb-mi/MIUtilVariant.h
+++ b/tools/lldb-mi/MIUtilVariant.h
@@ -6,18 +6,6 @@
// 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.
//--
diff --git a/tools/lldb-mi/Platform.cpp b/tools/lldb-mi/Platform.cpp
index 6ff998d2265f..7e2eabf51b42 100644
--- a/tools/lldb-mi/Platform.cpp
+++ b/tools/lldb-mi/Platform.cpp
@@ -23,65 +23,12 @@ BOOL WINAPI CtrlHandler(DWORD ctrlType)
{
if (_ctrlHandler != NULL)
{
- _ctrlHandler(0);
+ _ctrlHandler(SIGINT);
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)
{
@@ -93,12 +40,6 @@ signal(int sig, sighandler_t sigFunc)
SetConsoleCtrlHandler(CtrlHandler, TRUE);
}
break;
- case (SIGPIPE):
- case (SIGWINCH):
- case (SIGTSTP):
- case (SIGCONT):
- // ignore these for now
- break;
default:
assert(!"Not implemented!");
}
diff --git a/tools/lldb-mi/Platform.h b/tools/lldb-mi/Platform.h
index 7c351310b255..093ceac0fb9d 100644
--- a/tools/lldb-mi/Platform.h
+++ b/tools/lldb-mi/Platform.h
@@ -89,6 +89,7 @@ extern sighandler_t signal(int sig, sighandler_t);
#else
#include <inttypes.h>
+#include <limits.h>
#include <getopt.h>
#include <libgen.h>
@@ -96,14 +97,7 @@ extern sighandler_t signal(int sig, sighandler_t);
#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-server/LLDBServerUtilities.cpp b/tools/lldb-server/LLDBServerUtilities.cpp
new file mode 100644
index 000000000000..8df4875e5d1d
--- /dev/null
+++ b/tools/lldb-server/LLDBServerUtilities.cpp
@@ -0,0 +1,67 @@
+//===-- LLDBServerUtilities.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LLDBServerUtilities.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Interpreter/Args.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private::lldb_server;
+using namespace llvm;
+
+bool
+LLDBServerUtilities::SetupLogging(const std::string& log_file,
+ const StringRef& log_channels,
+ uint32_t log_options)
+{
+ lldb::StreamSP log_stream_sp;
+ if (log_file.empty())
+ {
+ log_stream_sp.reset(new StreamFile(stdout, false));
+ }
+ else
+ {
+ uint32_t options = File::eOpenOptionWrite | File::eOpenOptionCanCreate |
+ File::eOpenOptionCloseOnExec | File::eOpenOptionAppend;
+ if (!(log_options & LLDB_LOG_OPTION_APPEND))
+ options |= File::eOpenOptionTruncate;
+
+ log_stream_sp.reset(new StreamFile(log_file.c_str(), options));
+ }
+
+ SmallVector<StringRef, 32> channel_array;
+ log_channels.split(channel_array, ":");
+ for (auto channel_with_categories : channel_array)
+ {
+ StreamString error_stream;
+ Args channel_then_categories(channel_with_categories);
+ std::string channel(channel_then_categories.GetArgumentAtIndex(0));
+ channel_then_categories.Shift (); // Shift off the channel
+
+ bool success = Log::EnableLogChannel(log_stream_sp,
+ log_options,
+ channel.c_str(),
+ channel_then_categories.GetConstArgumentVector(),
+ error_stream);
+ if (!success)
+ {
+ fprintf(stderr, "Unable to open log file '%s' for channel \"%s\"\n",
+ log_file.c_str(),
+ channel_with_categories.str().c_str());
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/tools/lldb-server/LLDBServerUtilities.h b/tools/lldb-server/LLDBServerUtilities.h
new file mode 100644
index 000000000000..cab892a5edc6
--- /dev/null
+++ b/tools/lldb-server/LLDBServerUtilities.h
@@ -0,0 +1,25 @@
+//===-- LLDBServerUtilities.h -----------------------------------*- 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 <string>
+
+namespace lldb_private {
+namespace lldb_server {
+
+class LLDBServerUtilities
+{
+public:
+ static bool
+ SetupLogging(const std::string& log_file, const llvm::StringRef& log_channels, uint32_t log_options);
+};
+
+}
+}
diff --git a/tools/lldb-server/exports b/tools/lldb-server/exports
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tools/lldb-server/exports
diff --git a/tools/lldb-server/lldb-gdbserver.cpp b/tools/lldb-server/lldb-gdbserver.cpp
new file mode 100644
index 000000000000..a286e3df0de4
--- /dev/null
+++ b/tools/lldb-server/lldb-gdbserver.cpp
@@ -0,0 +1,698 @@
+//===-- lldb-gdbserver.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 <errno.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _WIN32
+#include <signal.h>
+#include <unistd.h>
+#endif
+
+// C++ Includes
+
+// Other libraries and framework includes
+#include "llvm/ADT/StringRef.h"
+
+#include "lldb/Core/ConnectionMachPort.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Host/Pipe.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Target/Platform.h"
+#include "LLDBServerUtilities.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
+
+#ifndef LLGS_PROGRAM_NAME
+#define LLGS_PROGRAM_NAME "lldb-server"
+#endif
+
+#ifndef LLGS_VERSION_STR
+#define LLGS_VERSION_STR "local_build"
+#endif
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::lldb_server;
+using namespace lldb_private::process_gdb_remote;
+
+// lldb-gdbserver state
+
+namespace
+{
+HostThread s_listen_thread;
+ std::unique_ptr<ConnectionFileDescriptor> s_listen_connection_up;
+ std::string s_listen_url;
+}
+
+//----------------------------------------------------------------------
+// option descriptors for getopt_long_only()
+//----------------------------------------------------------------------
+
+static int g_debug = 0;
+static int g_verbose = 0;
+
+static struct option g_long_options[] =
+{
+ { "debug", no_argument, &g_debug, 1 },
+ { "platform", required_argument, NULL, 'p' },
+ { "verbose", no_argument, &g_verbose, 1 },
+ { "log-file", required_argument, NULL, 'l' },
+ { "log-channels", required_argument, NULL, 'c' },
+ { "attach", required_argument, NULL, 'a' },
+ { "named-pipe", required_argument, NULL, 'N' },
+ { "pipe", required_argument, NULL, 'U' },
+ { "native-regs", no_argument, NULL, 'r' }, // Specify to use the native registers instead of the gdb defaults for the architecture. NOTE: this is a do-nothing arg as it's behavior is default now. FIXME remove call from lldb-platform.
+ { "reverse-connect", no_argument, NULL, 'R' }, // Specifies that llgs attaches to the client address:port rather than llgs listening for a connection from address on port.
+ { "setsid", no_argument, NULL, 'S' }, // Call setsid() to make llgs run in its own session.
+ { NULL, 0, NULL, 0 }
+};
+
+
+//----------------------------------------------------------------------
+// Watch for signals
+//----------------------------------------------------------------------
+static int g_sigpipe_received = 0;
+static int g_sighup_received_count = 0;
+
+#ifndef _WIN32
+
+static void
+signal_handler(int signo)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ fprintf (stderr, "lldb-server:%s received signal %d\n", __FUNCTION__, signo);
+ if (log)
+ log->Printf ("lldb-server:%s received signal %d", __FUNCTION__, signo);
+
+ switch (signo)
+ {
+ case SIGPIPE:
+ g_sigpipe_received = 1;
+ break;
+ case SIGHUP:
+ ++g_sighup_received_count;
+
+ // For now, swallow SIGHUP.
+ if (log)
+ log->Printf ("lldb-server:%s swallowing SIGHUP (receive count=%d)", __FUNCTION__, g_sighup_received_count);
+ signal (SIGHUP, signal_handler);
+ break;
+ }
+}
+#endif // #ifndef _WIN32
+
+static void
+display_usage (const char *progname, const char* subcommand)
+{
+ fprintf(stderr, "Usage:\n %s %s "
+ "[--log-file log-file-name] "
+ "[--log-channels log-channel-list] "
+ "[--platform platform_name] "
+ "[--setsid] "
+ "[--named-pipe named-pipe-path] "
+ "[--native-regs] "
+ "[--attach pid] "
+ "[[HOST]:PORT] "
+ "[-- PROGRAM ARG1 ARG2 ...]\n", progname, subcommand);
+ exit(0);
+}
+
+static void
+dump_available_platforms (FILE *output_file)
+{
+ fprintf (output_file, "Available platform plugins:\n");
+ for (int i = 0; ; ++i)
+ {
+ const char *plugin_name = PluginManager::GetPlatformPluginNameAtIndex (i);
+ const char *plugin_desc = PluginManager::GetPlatformPluginDescriptionAtIndex (i);
+
+ if (!plugin_name || !plugin_desc)
+ break;
+
+ fprintf (output_file, "%s\t%s\n", plugin_name, plugin_desc);
+ }
+
+ if ( Platform::GetHostPlatform () )
+ {
+ // add this since the default platform doesn't necessarily get registered by
+ // the plugin name (e.g. 'host' doesn't show up as a
+ // registered platform plugin even though it's the default).
+ fprintf (output_file, "%s\tDefault platform for this host.\n", Platform::GetHostPlatform ()->GetPluginName ().AsCString ());
+ }
+}
+
+static lldb::PlatformSP
+setup_platform (const std::string &platform_name)
+{
+ lldb::PlatformSP platform_sp;
+
+ if (platform_name.empty())
+ {
+ printf ("using the default platform: ");
+ platform_sp = Platform::GetHostPlatform ();
+ printf ("%s\n", platform_sp->GetPluginName ().AsCString ());
+ return platform_sp;
+ }
+
+ Error error;
+ platform_sp = Platform::Create (lldb_private::ConstString(platform_name), error);
+ if (error.Fail ())
+ {
+ // the host platform isn't registered with that name (at
+ // least, not always. Check if the given name matches
+ // the default platform name. If so, use it.
+ if ( Platform::GetHostPlatform () && ( Platform::GetHostPlatform ()->GetPluginName () == ConstString (platform_name.c_str()) ) )
+ {
+ platform_sp = Platform::GetHostPlatform ();
+ }
+ else
+ {
+ fprintf (stderr, "error: failed to create platform with name '%s'\n", platform_name.c_str());
+ dump_available_platforms (stderr);
+ exit (1);
+ }
+ }
+ printf ("using platform: %s\n", platform_name.c_str ());
+
+ return platform_sp;
+}
+
+void
+handle_attach_to_pid (GDBRemoteCommunicationServerLLGS &gdb_server, lldb::pid_t pid)
+{
+ Error error = gdb_server.AttachToProcess (pid);
+ if (error.Fail ())
+ {
+ fprintf (stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid, error.AsCString());
+ exit(1);
+ }
+}
+
+void
+handle_attach_to_process_name (GDBRemoteCommunicationServerLLGS &gdb_server, const std::string &process_name)
+{
+ // FIXME implement.
+}
+
+void
+handle_attach (GDBRemoteCommunicationServerLLGS &gdb_server, const std::string &attach_target)
+{
+ assert (!attach_target.empty () && "attach_target cannot be empty");
+
+ // First check if the attach_target is convertible to a long. If so, we'll use it as a pid.
+ char *end_p = nullptr;
+ const long int pid = strtol (attach_target.c_str (), &end_p, 10);
+
+ // We'll call it a match if the entire argument is consumed.
+ if (end_p && static_cast<size_t> (end_p - attach_target.c_str ()) == attach_target.size ())
+ handle_attach_to_pid (gdb_server, static_cast<lldb::pid_t> (pid));
+ else
+ handle_attach_to_process_name (gdb_server, attach_target);
+}
+
+void
+handle_launch (GDBRemoteCommunicationServerLLGS &gdb_server, int argc, const char *const argv[])
+{
+ Error error;
+ error = gdb_server.SetLaunchArguments (argv, argc);
+ if (error.Fail ())
+ {
+ fprintf (stderr, "error: failed to set launch args for '%s': %s\n", argv[0], error.AsCString());
+ exit(1);
+ }
+
+ unsigned int launch_flags = eLaunchFlagStopAtEntry | eLaunchFlagDebug;
+
+ error = gdb_server.SetLaunchFlags (launch_flags);
+ if (error.Fail ())
+ {
+ fprintf (stderr, "error: failed to set launch flags for '%s': %s\n", argv[0], error.AsCString());
+ exit(1);
+ }
+
+ error = gdb_server.LaunchProcess ();
+ if (error.Fail ())
+ {
+ fprintf (stderr, "error: failed to launch '%s': %s\n", argv[0], error.AsCString());
+ exit(1);
+ }
+}
+
+static lldb::thread_result_t
+ListenThread (lldb::thread_arg_t /* arg */)
+{
+ Error error;
+
+ if (s_listen_connection_up)
+ {
+ // Do the listen on another thread so we can continue on...
+ if (s_listen_connection_up->Connect(s_listen_url.c_str(), &error) != eConnectionStatusSuccess)
+ s_listen_connection_up.reset();
+ }
+ return nullptr;
+}
+
+static Error
+StartListenThread (const char *hostname, uint16_t port)
+{
+ Error error;
+ if (s_listen_thread.IsJoinable())
+ {
+ error.SetErrorString("listen thread already running");
+ }
+ else
+ {
+ char listen_url[512];
+ if (hostname && hostname[0])
+ snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port);
+ else
+ snprintf(listen_url, sizeof(listen_url), "listen://%i", port);
+
+ s_listen_url = listen_url;
+ s_listen_connection_up.reset (new ConnectionFileDescriptor ());
+ s_listen_thread = ThreadLauncher::LaunchThread(listen_url, ListenThread, nullptr, &error);
+ }
+ return error;
+}
+
+static bool
+JoinListenThread ()
+{
+ if (s_listen_thread.IsJoinable())
+ s_listen_thread.Join(nullptr);
+ return true;
+}
+
+Error
+WritePortToPipe(Pipe &port_pipe, const uint16_t port)
+{
+ char port_str[64];
+ const auto port_str_len = ::snprintf(port_str, sizeof(port_str), "%u", port);
+
+ size_t bytes_written = 0;
+ // Write the port number as a C string with the NULL terminator.
+ return port_pipe.Write(port_str, port_str_len + 1, bytes_written);
+}
+
+Error
+writePortToPipe(const char *const named_pipe_path, const uint16_t port)
+{
+ Pipe port_name_pipe;
+ // Wait for 10 seconds for pipe to be opened.
+ auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false,
+ std::chrono::seconds{10});
+ if (error.Fail())
+ return error;
+ return WritePortToPipe(port_name_pipe, port);
+}
+
+Error
+writePortToPipe(int unnamed_pipe_fd, const uint16_t port)
+{
+#if defined(_WIN32)
+ return Error("Unnamed pipes are not supported on Windows.");
+#else
+ Pipe port_pipe{Pipe::kInvalidDescriptor, unnamed_pipe_fd};
+ return WritePortToPipe(port_pipe, port);
+#endif
+}
+
+void
+ConnectToRemote(GDBRemoteCommunicationServerLLGS &gdb_server,
+ bool reverse_connect, const char *const host_and_port,
+ const char *const progname, const char *const subcommand,
+ const char *const named_pipe_path, int unnamed_pipe_fd)
+{
+ Error error;
+
+ if (host_and_port && host_and_port[0])
+ {
+ // Parse out host and port.
+ std::string final_host_and_port;
+ std::string connection_host;
+ std::string connection_port;
+ uint32_t connection_portno = 0;
+
+ // If host_and_port starts with ':', default the host to be "localhost" and expect the remainder to be the port.
+ if (host_and_port[0] == ':')
+ final_host_and_port.append ("localhost");
+ final_host_and_port.append (host_and_port);
+
+ const std::string::size_type colon_pos = final_host_and_port.find (':');
+ if (colon_pos != std::string::npos)
+ {
+ connection_host = final_host_and_port.substr (0, colon_pos);
+ connection_port = final_host_and_port.substr (colon_pos + 1);
+ connection_portno = StringConvert::ToUInt32 (connection_port.c_str (), 0);
+ }
+ else
+ {
+ fprintf (stderr, "failed to parse host and port from connection string '%s'\n", final_host_and_port.c_str ());
+ display_usage (progname, subcommand);
+ exit (1);
+ }
+
+ if (reverse_connect)
+ {
+ // llgs will connect to the gdb-remote client.
+
+ // Ensure we have a port number for the connection.
+ if (connection_portno == 0)
+ {
+ fprintf (stderr, "error: port number must be specified on when using reverse connect");
+ exit (1);
+ }
+
+ // Build the connection string.
+ char connection_url[512];
+ snprintf(connection_url, sizeof(connection_url), "connect://%s", final_host_and_port.c_str ());
+
+ // Create the connection.
+ std::unique_ptr<ConnectionFileDescriptor> connection_up (new ConnectionFileDescriptor ());
+ connection_up.reset (new ConnectionFileDescriptor ());
+ auto connection_result = connection_up->Connect (connection_url, &error);
+ if (connection_result != eConnectionStatusSuccess)
+ {
+ fprintf (stderr, "error: failed to connect to client at '%s' (connection status: %d)", connection_url, static_cast<int> (connection_result));
+ exit (-1);
+ }
+ if (error.Fail ())
+ {
+ fprintf (stderr, "error: failed to connect to client at '%s': %s", connection_url, error.AsCString ());
+ exit (-1);
+ }
+
+ // We're connected.
+ printf ("Connection established.\n");
+ gdb_server.SetConnection (connection_up.release());
+ }
+ else
+ {
+ // llgs will listen for connections on the given port from the given address.
+ // Start the listener on a new thread. We need to do this so we can resolve the
+ // bound listener port.
+ StartListenThread(connection_host.c_str (), static_cast<uint16_t> (connection_portno));
+ printf ("Listening to port %s for a connection from %s...\n", connection_port.c_str (), connection_host.c_str ());
+
+ // If we have a named pipe to write the port number back to, do that now.
+ if (named_pipe_path && named_pipe_path[0] && connection_portno == 0)
+ {
+ const uint16_t bound_port = s_listen_connection_up->GetListeningPort (10);
+ if (bound_port > 0)
+ {
+ error = writePortToPipe (named_pipe_path, bound_port);
+ if (error.Fail ())
+ {
+ fprintf (stderr, "failed to write to the named pipe \'%s\': %s", named_pipe_path, error.AsCString());
+ }
+ }
+ else
+ {
+ fprintf (stderr, "unable to get the bound port for the listening connection\n");
+ }
+ }
+
+ // If we have an unnamed pipe to write the port number back to, do that now.
+ if (unnamed_pipe_fd >= 0 && connection_portno == 0)
+ {
+ const uint16_t bound_port = s_listen_connection_up->GetListeningPort(10);
+ if (bound_port > 0)
+ {
+ error = writePortToPipe(unnamed_pipe_fd, bound_port);
+ if (error.Fail())
+ {
+ fprintf(stderr, "failed to write to the unnamed pipe: %s",
+ error.AsCString());
+ }
+ }
+ else
+ {
+ fprintf(stderr, "unable to get the bound port for the listening connection\n");
+ }
+ }
+
+ // Join the listener thread.
+ if (!JoinListenThread ())
+ {
+ fprintf (stderr, "failed to join the listener thread\n");
+ display_usage (progname, subcommand);
+ exit (1);
+ }
+
+ // Ensure we connected.
+ if (s_listen_connection_up)
+ {
+ printf ("Connection established '%s'\n", s_listen_connection_up->GetURI().c_str());
+ gdb_server.SetConnection (s_listen_connection_up.release());
+ }
+ else
+ {
+ fprintf (stderr, "failed to connect to '%s': %s\n", final_host_and_port.c_str (), error.AsCString ());
+ display_usage (progname, subcommand);
+ exit (1);
+ }
+ }
+ }
+
+ if (gdb_server.IsConnected())
+ {
+ // After we connected, we need to get an initial ack from...
+ if (gdb_server.HandshakeWithClient(&error))
+ {
+ // We'll use a half a second timeout interval so that an exit conditions can
+ // be checked that often.
+ const uint32_t TIMEOUT_USEC = 500000;
+
+ bool interrupt = false;
+ bool done = false;
+ while (!interrupt && !done && (g_sighup_received_count < 2))
+ {
+ const GDBRemoteCommunication::PacketResult result = gdb_server.GetPacketAndSendResponse (TIMEOUT_USEC, error, interrupt, done);
+ if ((result != GDBRemoteCommunication::PacketResult::Success) &&
+ (result != GDBRemoteCommunication::PacketResult::ErrorReplyTimeout))
+ {
+ // We're bailing out - we only support successful handling and timeouts.
+ fprintf(stderr, "leaving packet loop due to PacketResult %d\n", result);
+ break;
+ }
+ }
+
+ if (error.Fail())
+ {
+ fprintf(stderr, "error: %s\n", error.AsCString());
+ }
+ }
+ else
+ {
+ fprintf(stderr, "error: handshake with client failed\n");
+ }
+ }
+ else
+ {
+ fprintf (stderr, "no connection information provided, unable to run\n");
+ display_usage (progname, subcommand);
+ exit (1);
+ }
+}
+
+//----------------------------------------------------------------------
+// main
+//----------------------------------------------------------------------
+int
+main_gdbserver (int argc, char *argv[])
+{
+#ifndef _WIN32
+ // Setup signal handlers first thing.
+ signal (SIGPIPE, signal_handler);
+ signal (SIGHUP, signal_handler);
+#endif
+#ifdef __linux__
+ // Block delivery of SIGCHLD on linux. NativeProcessLinux will read it using signalfd.
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+#endif
+
+ const char *progname = argv[0];
+ const char *subcommand = argv[1];
+ argc--;
+ argv++;
+ int long_option_index = 0;
+ Error error;
+ int ch;
+ std::string platform_name;
+ std::string attach_target;
+ std::string named_pipe_path;
+ std::string log_file;
+ StringRef log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
+ int unnamed_pipe_fd = -1;
+ bool reverse_connect = false;
+
+ // ProcessLaunchInfo launch_info;
+ ProcessAttachInfo attach_info;
+
+ bool show_usage = false;
+ int option_error = 0;
+#if __GLIBC__
+ optind = 0;
+#else
+ optreset = 1;
+ optind = 1;
+#endif
+
+ std::string short_options(OptionParser::GetShortOptionString(g_long_options));
+
+ while ((ch = getopt_long_only(argc, argv, short_options.c_str(), g_long_options, &long_option_index)) != -1)
+ {
+ switch (ch)
+ {
+ case 0: // Any optional that auto set themselves will return 0
+ break;
+
+ case 'l': // Set Log File
+ if (optarg && optarg[0])
+ log_file.assign(optarg);
+ break;
+
+ case 'c': // Log Channels
+ if (optarg && optarg[0])
+ log_channels = StringRef(optarg);
+ break;
+
+ case 'p': // platform name
+ if (optarg && optarg[0])
+ platform_name = optarg;
+ break;
+
+ case 'N': // named pipe
+ if (optarg && optarg[0])
+ named_pipe_path = optarg;
+ break;
+
+ case 'U': // unnamed pipe
+ if (optarg && optarg[0])
+ unnamed_pipe_fd = StringConvert::ToUInt32(optarg, -1);
+
+ case 'r':
+ // Do nothing, native regs is the default these days
+ break;
+
+ case 'R':
+ reverse_connect = true;
+ break;
+
+#ifndef _WIN32
+ case 'S':
+ // Put llgs into a new session. Terminals group processes
+ // into sessions and when a special terminal key sequences
+ // (like control+c) are typed they can cause signals to go out to
+ // all processes in a session. Using this --setsid (-S) option
+ // will cause debugserver to run in its own sessions and be free
+ // from such issues.
+ //
+ // This is useful when llgs is spawned from a command
+ // line application that uses llgs to do the debugging,
+ // yet that application doesn't want llgs receiving the
+ // signals sent to the session (i.e. dying when anyone hits ^C).
+ {
+ const ::pid_t new_sid = setsid();
+ if (new_sid == -1)
+ {
+ const char *errno_str = strerror(errno);
+ fprintf (stderr, "failed to set new session id for %s (%s)\n", LLGS_PROGRAM_NAME, errno_str ? errno_str : "<no error string>");
+ }
+ }
+ break;
+#endif
+
+ case 'a': // attach {pid|process_name}
+ if (optarg && optarg[0])
+ attach_target = optarg;
+ break;
+
+ case 'h': /* fall-through is intentional */
+ case '?':
+ show_usage = true;
+ break;
+ }
+ }
+
+ if (show_usage || option_error)
+ {
+ display_usage(progname, subcommand);
+ exit(option_error);
+ }
+
+ if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
+ return -1;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_VERBOSE));
+ if (log)
+ {
+ log->Printf ("lldb-server launch");
+ for (int i = 0; i < argc; i++)
+ {
+ log->Printf ("argv[%i] = '%s'", i, argv[i]);
+ }
+ }
+
+ // Skip any options we consumed with getopt_long_only.
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ {
+ display_usage(progname, subcommand);
+ exit(255);
+ }
+
+ // Setup the platform that GDBRemoteCommunicationServerLLGS will use.
+ lldb::PlatformSP platform_sp = setup_platform (platform_name);
+
+ GDBRemoteCommunicationServerLLGS gdb_server (platform_sp);
+
+ const char *const host_and_port = argv[0];
+ argc -= 1;
+ argv += 1;
+
+ // Any arguments left over are for the program that we need to launch. If there
+ // are no arguments, then the GDB server will start up and wait for an 'A' packet
+ // to launch a program, or a vAttach packet to attach to an existing process, unless
+ // explicitly asked to attach with the --attach={pid|program_name} form.
+ if (!attach_target.empty ())
+ handle_attach (gdb_server, attach_target);
+ else if (argc > 0)
+ handle_launch (gdb_server, argc, argv);
+
+ // Print version info.
+ printf("%s-%s", LLGS_PROGRAM_NAME, LLGS_VERSION_STR);
+
+ ConnectToRemote(gdb_server, reverse_connect,
+ host_and_port, progname, subcommand,
+ named_pipe_path.c_str(), unnamed_pipe_fd);
+
+ fprintf(stderr, "lldb-server exiting...\n");
+
+ return 0;
+}
diff --git a/tools/lldb-platform/lldb-platform.cpp b/tools/lldb-server/lldb-platform.cpp
index f1c1a982850a..33ba1ad1ef98 100644
--- a/tools/lldb-platform/lldb-platform.cpp
+++ b/tools/lldb-server/lldb-platform.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
#include <errno.h>
#if defined(__APPLE__)
@@ -19,44 +17,46 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/wait.h>
// C++ Includes
// Other libraries and framework includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Error.h"
-#include "lldb/Core/ConnectionMachPort.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Core/StreamFile.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/HostGetOpt.h"
#include "lldb/Host/OptionParser.h"
-#include "lldb/Interpreter/CommandInterpreter.h"
-#include "lldb/Interpreter/CommandReturnObject.h"
-#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
+#include "lldb/Host/Socket.h"
+#include "LLDBServerUtilities.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
+
using namespace lldb;
using namespace lldb_private;
+using namespace lldb_private::lldb_server;
+using namespace lldb_private::process_gdb_remote;
+using namespace llvm;
//----------------------------------------------------------------------
// option descriptors for getopt_long_only()
//----------------------------------------------------------------------
-int g_debug = 0;
-int g_verbose = 0;
-int g_stay_alive = 0;
+static int g_debug = 0;
+static int g_verbose = 0;
+static int g_server = 0;
static struct option g_long_options[] =
{
{ "debug", no_argument, &g_debug, 1 },
{ "verbose", no_argument, &g_verbose, 1 },
- { "stay-alive", no_argument, &g_stay_alive, 1 },
+ { "log-file", required_argument, NULL, 'l' },
+ { "log-channels", required_argument, NULL, 'c' },
{ "listen", required_argument, NULL, 'L' },
{ "port-offset", required_argument, NULL, 'p' },
{ "gdbserver-port", required_argument, NULL, 'P' },
{ "min-gdbserver-port", required_argument, NULL, 'm' },
{ "max-gdbserver-port", required_argument, NULL, 'M' },
- { "lldb-command", required_argument, NULL, 'c' },
+ { "server", no_argument, &g_server, 1 },
{ NULL, 0, NULL, 0 }
};
@@ -68,11 +68,10 @@ static struct option g_long_options[] =
#define HIGH_PORT (49151u)
#endif
-
//----------------------------------------------------------------------
// Watch for signals
//----------------------------------------------------------------------
-void
+static void
signal_handler(int signo)
{
switch (signo)
@@ -81,16 +80,16 @@ signal_handler(int signo)
// Use SIGINT first, if that does not work, use SIGHUP as a last resort.
// And we should not call exit() here because it results in the global destructors
// to be invoked and wreaking havoc on the threads still running.
- Host::SystemLog(Host::eSystemLogWarning, "SIGHUP received, exiting lldb-platform...\n");
+ Host::SystemLog(Host::eSystemLogWarning, "SIGHUP received, exiting lldb-server...\n");
abort();
break;
}
}
static void
-display_usage (const char *progname)
+display_usage (const char *progname, const char *subcommand)
{
- fprintf(stderr, "Usage:\n %s [--log-file log-file-path] [--log-flags flags] --listen port\n", progname);
+ fprintf(stderr, "Usage:\n %s %s [--log-file log-file-name] [--log-channels log-channel-list] --server --listen port\n", progname, subcommand);
exit(0);
}
@@ -98,31 +97,30 @@ display_usage (const char *progname)
// main
//----------------------------------------------------------------------
int
-main (int argc, char *argv[])
+main_platform (int argc, char *argv[])
{
const char *progname = argv[0];
+ const char *subcommand = argv[1];
+ argc--;
+ argv++;
signal (SIGPIPE, SIG_IGN);
signal (SIGHUP, signal_handler);
int long_option_index = 0;
Error error;
std::string listen_host_port;
int ch;
- Debugger::Initialize(NULL);
-
- lldb::DebuggerSP debugger_sp = Debugger::CreateInstance ();
- debugger_sp->SetInputFileHandle(stdin, false);
- debugger_sp->SetOutputFileHandle(stdout, false);
- debugger_sp->SetErrorFileHandle(stderr, false);
-
- GDBRemoteCommunicationServer::PortMap gdbserver_portmap;
+ std::string log_file;
+ StringRef log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
+
+ GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
int min_gdbserver_port = 0;
int max_gdbserver_port = 0;
uint16_t port_offset = 0;
- std::vector<std::string> lldb_commands;
bool show_usage = false;
int option_error = 0;
+ int socket_error = -1;
std::string short_options(OptionParser::GetShortOptionString(g_long_options));
@@ -144,6 +142,16 @@ main (int argc, char *argv[])
listen_host_port.append (optarg);
break;
+ case 'l': // Set Log File
+ if (optarg && optarg[0])
+ log_file.assign(optarg);
+ break;
+
+ case 'c': // Log Channels
+ if (optarg && optarg[0])
+ log_channels = StringRef(optarg);
+ break;
+
case 'p':
{
char *end = NULL;
@@ -198,10 +206,6 @@ main (int argc, char *argv[])
}
}
break;
-
- case 'c':
- lldb_commands.push_back(optarg);
- break;
case 'h': /* fall-through is intentional */
case '?':
@@ -210,6 +214,9 @@ main (int argc, char *argv[])
}
}
+ if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
+ return -1;
+
// Make a port map for a port range that was specified.
if (min_gdbserver_port < max_gdbserver_port)
{
@@ -220,7 +227,6 @@ main (int argc, char *argv[])
{
fprintf (stderr, "error: --min-gdbserver-port (%u) is greater than --max-gdbserver-port (%u)\n", min_gdbserver_port, max_gdbserver_port);
option_error = 3;
-
}
// Print usage and exit if no listening port is specified.
@@ -229,82 +235,102 @@ main (int argc, char *argv[])
if (show_usage || option_error)
{
- display_usage(progname);
+ display_usage(progname, subcommand);
exit(option_error);
}
- // Execute any LLDB commands that we were asked to evaluate.
- for (const auto &lldb_command : lldb_commands)
+ std::unique_ptr<Socket> listening_socket_up;
+ Socket *socket = nullptr;
+ const bool children_inherit_listen_socket = false;
+
+ // the test suite makes many connections in parallel, let's not miss any.
+ // The highest this should get reasonably is a function of the number
+ // of target CPUs. For now, let's just use 100
+ const int backlog = 100;
+ error = Socket::TcpListen(listen_host_port.c_str(), children_inherit_listen_socket, socket, NULL, backlog);
+ if (error.Fail())
{
- lldb_private::CommandReturnObject result;
- printf("(lldb) %s\n", lldb_command.c_str());
- debugger_sp->GetCommandInterpreter().HandleCommand(lldb_command.c_str(), eLazyBoolNo, result);
- const char *output = result.GetOutputData();
- if (output && output[0])
- puts(output);
+ printf("error: %s\n", error.AsCString());
+ exit(socket_error);
}
-
+ listening_socket_up.reset(socket);
+ printf ("Listening for a connection from %u...\n", listening_socket_up->GetLocalPortNumber());
do {
- GDBRemoteCommunicationServer gdb_server (true);
+ GDBRemoteCommunicationServerPlatform platform;
if (port_offset > 0)
- gdb_server.SetPortOffset(port_offset);
+ platform.SetPortOffset(port_offset);
if (!gdbserver_portmap.empty())
{
- gdb_server.SetPortMap(std::move(gdbserver_portmap));
+ platform.SetPortMap(std::move(gdbserver_portmap));
}
- if (!listen_host_port.empty())
+ const bool children_inherit_accept_socket = true;
+ socket = nullptr;
+ error = listening_socket_up->BlockingAccept(listen_host_port.c_str(), children_inherit_accept_socket, socket);
+ if (error.Fail())
{
- std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
- if (conn_ap.get())
+ printf ("error: %s\n", error.AsCString());
+ exit(socket_error);
+ }
+ printf ("Connection established.\n");
+ if (g_server)
+ {
+ // Collect child zombie processes.
+ while (waitpid(-1, nullptr, WNOHANG) > 0);
+ if (fork())
{
- std::string connect_url ("listen://");
- connect_url.append(listen_host_port.c_str());
+ // Parent doesn't need a connection to the lldb client
+ delete socket;
+ socket = nullptr;
- printf ("Listening for a connection from %s...\n", listen_host_port.c_str());
- if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
- {
- printf ("Connection established.\n");
- gdb_server.SetConnection (conn_ap.release());
- }
- else
- {
- printf ("error: %s\n", error.AsCString());
- }
+ // Parent will continue to listen for new connections.
+ continue;
+ }
+ else
+ {
+ // Child process will handle the connection and exit.
+ g_server = 0;
+ // Listening socket is owned by parent process.
+ listening_socket_up.release();
}
+ }
+ else
+ {
+ // If not running as a server, this process will not accept
+ // connections while a connection is active.
+ listening_socket_up.reset();
+ }
+ platform.SetConnection (new ConnectionFileDescriptor(socket));
- if (gdb_server.IsConnected())
+ if (platform.IsConnected())
+ {
+ // After we connected, we need to get an initial ack from...
+ if (platform.HandshakeWithClient(&error))
{
- // After we connected, we need to get an initial ack from...
- if (gdb_server.HandshakeWithClient(&error))
+ bool interrupt = false;
+ bool done = false;
+ while (!interrupt && !done)
{
- bool interrupt = false;
- bool done = false;
- while (!interrupt && !done)
- {
- if (gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done) != GDBRemoteCommunication::PacketResult::Success)
- break;
- }
-
- if (error.Fail())
- {
- fprintf(stderr, "error: %s\n", error.AsCString());
- }
+ if (platform.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done) != GDBRemoteCommunication::PacketResult::Success)
+ break;
}
- else
+
+ if (error.Fail())
{
- fprintf(stderr, "error: handshake with client failed\n");
+ fprintf(stderr, "error: %s\n", error.AsCString());
}
}
+ else
+ {
+ fprintf(stderr, "error: handshake with client failed\n");
+ }
}
- } while (g_stay_alive);
-
- Debugger::Terminate();
+ } while (g_server);
- fprintf(stderr, "lldb-platform exiting...\n");
+ fprintf(stderr, "lldb-server exiting...\n");
return 0;
}
diff --git a/tools/lldb-server/lldb-server.cpp b/tools/lldb-server/lldb-server.cpp
new file mode 100644
index 000000000000..ec92b094f485
--- /dev/null
+++ b/tools/lldb-server/lldb-server.cpp
@@ -0,0 +1,76 @@
+//===-- lldb-server.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/Initialization/SystemLifetimeManager.h"
+#include "lldb/Initialization/SystemInitializerCommon.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/ManagedStatic.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static llvm::ManagedStatic<lldb_private::SystemLifetimeManager> g_debugger_lifetime;
+
+static void
+display_usage (const char *progname)
+{
+ fprintf(stderr, "Usage:\n"
+ " %s g[dbserver] [options]\n"
+ " %s p[latform] [options]\n"
+ "Invoke subcommand for additional help\n", progname, progname);
+ exit(0);
+}
+
+// Forward declarations of subcommand main methods.
+int main_gdbserver (int argc, char *argv[]);
+int main_platform (int argc, char *argv[]);
+
+static void
+initialize ()
+{
+ g_debugger_lifetime->Initialize(llvm::make_unique<lldb_private::SystemInitializerCommon>(), nullptr);
+}
+
+static void
+terminate ()
+{
+ g_debugger_lifetime->Terminate();
+}
+
+//----------------------------------------------------------------------
+// main
+//----------------------------------------------------------------------
+int
+main (int argc, char *argv[])
+{
+ int option_error = 0;
+ const char *progname = argv[0];
+ if (argc < 2)
+ {
+ display_usage(progname);
+ exit(option_error);
+ }
+ else if (argv[1][0] == 'g')
+ {
+ initialize();
+ main_gdbserver(argc, argv);
+ terminate();
+ }
+ else if (argv[1][0] == 'p')
+ {
+ initialize();
+ main_platform(argc, argv);
+ terminate();
+ }
+ else {
+ display_usage(progname);
+ exit(option_error);
+ }
+}