aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2015-07-03 16:57:06 +0000
committerEd Maste <emaste@FreeBSD.org>2015-07-03 16:57:06 +0000
commit5e95aa85bb660d45e9905ef1d7180b2678280660 (patch)
tree3c2e41c3be19b7fc7666ed45a5f91ec3b6e35f2a /source
parent12bd4897ff0678fa663e09d78ebc22dd255ceb86 (diff)
downloadsrc-vendor/lldb/lldb-r241361.tar.gz
src-vendor/lldb/lldb-r241361.zip
Import LLDB as of upstream SVN 241361 (git 612c075f)vendor/lldb/lldb-r241361
Diffstat (limited to 'source')
-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
443 files changed, 46348 insertions, 19605 deletions
diff --git a/source/API/SBAddress.cpp b/source/API/SBAddress.cpp
index d6e32b60059b..f95fcb8b3985 100644
--- a/source/API/SBAddress.cpp
+++ b/source/API/SBAddress.cpp
@@ -14,7 +14,9 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/LineEntry.h"
#include "lldb/Target/Target.h"
diff --git a/source/API/SBAttachInfo.cpp b/source/API/SBAttachInfo.cpp
new file mode 100644
index 000000000000..07446df27dff
--- /dev/null
+++ b/source/API/SBAttachInfo.cpp
@@ -0,0 +1,242 @@
+//===-- SBAttachInfo.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBAttachInfo.h"
+
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBListener.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBAttachInfo::SBAttachInfo () :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+}
+
+SBAttachInfo::SBAttachInfo (lldb::pid_t pid) :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+ m_opaque_sp->SetProcessID (pid);
+}
+
+SBAttachInfo::SBAttachInfo (const char *path, bool wait_for) :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+ if (path && path[0])
+ m_opaque_sp->GetExecutableFile().SetFile(path, false);
+ m_opaque_sp->SetWaitForLaunch (wait_for);
+}
+
+SBAttachInfo::SBAttachInfo (const SBAttachInfo &rhs) :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+ *m_opaque_sp = *rhs.m_opaque_sp;
+}
+
+SBAttachInfo::~SBAttachInfo()
+{
+}
+
+lldb_private::ProcessAttachInfo &
+SBAttachInfo::ref ()
+{
+ return *m_opaque_sp;
+}
+
+SBAttachInfo &
+SBAttachInfo::operator = (const SBAttachInfo &rhs)
+{
+ if (this != &rhs)
+ *m_opaque_sp = *rhs.m_opaque_sp;
+ return *this;
+}
+
+lldb::pid_t
+SBAttachInfo::GetProcessID ()
+{
+ return m_opaque_sp->GetProcessID();
+}
+
+void
+SBAttachInfo::SetProcessID (lldb::pid_t pid)
+{
+ m_opaque_sp->SetProcessID (pid);
+}
+
+
+uint32_t
+SBAttachInfo::GetResumeCount ()
+{
+ return m_opaque_sp->GetResumeCount();
+}
+
+void
+SBAttachInfo::SetResumeCount (uint32_t c)
+{
+ m_opaque_sp->SetResumeCount (c);
+}
+
+const char *
+SBAttachInfo::GetProcessPluginName ()
+{
+ return m_opaque_sp->GetProcessPluginName();
+}
+
+void
+SBAttachInfo::SetProcessPluginName (const char *plugin_name)
+{
+ return m_opaque_sp->SetProcessPluginName (plugin_name);
+}
+
+void
+SBAttachInfo::SetExecutable (const char *path)
+{
+ if (path && path[0])
+ m_opaque_sp->GetExecutableFile().SetFile(path, false);
+ else
+ m_opaque_sp->GetExecutableFile().Clear();
+}
+
+void
+SBAttachInfo::SetExecutable (SBFileSpec exe_file)
+{
+ if (exe_file.IsValid())
+ m_opaque_sp->GetExecutableFile() = exe_file.ref();
+ else
+ m_opaque_sp->GetExecutableFile().Clear();
+}
+
+bool
+SBAttachInfo::GetWaitForLaunch ()
+{
+ return m_opaque_sp->GetWaitForLaunch();
+}
+
+void
+SBAttachInfo::SetWaitForLaunch (bool b)
+{
+ m_opaque_sp->SetWaitForLaunch (b);
+}
+
+bool
+SBAttachInfo::GetIgnoreExisting ()
+{
+ return m_opaque_sp->GetIgnoreExisting();
+}
+
+void
+SBAttachInfo::SetIgnoreExisting (bool b)
+{
+ m_opaque_sp->SetIgnoreExisting (b);
+}
+
+uint32_t
+SBAttachInfo::GetUserID()
+{
+ return m_opaque_sp->GetUserID();
+}
+
+uint32_t
+SBAttachInfo::GetGroupID()
+{
+ return m_opaque_sp->GetGroupID();
+}
+
+bool
+SBAttachInfo::UserIDIsValid ()
+{
+ return m_opaque_sp->UserIDIsValid();
+}
+
+bool
+SBAttachInfo::GroupIDIsValid ()
+{
+ return m_opaque_sp->GroupIDIsValid();
+}
+
+void
+SBAttachInfo::SetUserID (uint32_t uid)
+{
+ m_opaque_sp->SetUserID (uid);
+}
+
+void
+SBAttachInfo::SetGroupID (uint32_t gid)
+{
+ m_opaque_sp->SetGroupID (gid);
+}
+
+uint32_t
+SBAttachInfo::GetEffectiveUserID()
+{
+ return m_opaque_sp->GetEffectiveUserID();
+}
+
+uint32_t
+SBAttachInfo::GetEffectiveGroupID()
+{
+ return m_opaque_sp->GetEffectiveGroupID();
+}
+
+bool
+SBAttachInfo::EffectiveUserIDIsValid ()
+{
+ return m_opaque_sp->EffectiveUserIDIsValid();
+}
+
+bool
+SBAttachInfo::EffectiveGroupIDIsValid ()
+{
+ return m_opaque_sp->EffectiveGroupIDIsValid ();
+}
+
+void
+SBAttachInfo::SetEffectiveUserID (uint32_t uid)
+{
+ m_opaque_sp->SetEffectiveUserID(uid);
+}
+
+void
+SBAttachInfo::SetEffectiveGroupID (uint32_t gid)
+{
+ m_opaque_sp->SetEffectiveGroupID(gid);
+}
+
+lldb::pid_t
+SBAttachInfo::GetParentProcessID ()
+{
+ return m_opaque_sp->GetParentProcessID();
+}
+
+void
+SBAttachInfo::SetParentProcessID (lldb::pid_t pid)
+{
+ m_opaque_sp->SetParentProcessID (pid);
+}
+
+bool
+SBAttachInfo::ParentProcessIDIsValid()
+{
+ return m_opaque_sp->ParentProcessIDIsValid();
+}
+
+SBListener
+SBAttachInfo::GetListener ()
+{
+ return SBListener(m_opaque_sp->GetListener());
+}
+
+void
+SBAttachInfo::SetListener (SBListener &listener)
+{
+ m_opaque_sp->SetListener(listener.GetSP());
+}
diff --git a/source/API/SBCommandInterpreter.cpp b/source/API/SBCommandInterpreter.cpp
index 193d06e4d920..d901e728105b 100644
--- a/source/API/SBCommandInterpreter.cpp
+++ b/source/API/SBCommandInterpreter.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/lldb-types.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Core/Listener.h"
@@ -20,6 +18,7 @@
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBCommandReturnObject.h"
#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBEvent.h"
#include "lldb/API/SBExecutionContext.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBTarget.h"
@@ -446,6 +445,37 @@ SBCommandInterpreter::GetDebugger ()
return sb_debugger;
}
+bool
+SBCommandInterpreter::GetPromptOnQuit()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->GetPromptOnQuit();
+ return false;
+}
+
+void
+SBCommandInterpreter::SetPromptOnQuit (bool b)
+{
+ if (m_opaque_ptr)
+ m_opaque_ptr->SetPromptOnQuit(b);
+}
+
+void
+SBCommandInterpreter::ResolveCommand(const char *command_line, SBCommandReturnObject &result)
+{
+ result.Clear();
+ if (command_line && m_opaque_ptr)
+ {
+ m_opaque_ptr->ResolveCommand(command_line, result.ref());
+ }
+ else
+ {
+ result->AppendError("SBCommandInterpreter or the command line is not valid");
+ result->SetStatus(eReturnStatusFailed);
+ }
+}
+
+
CommandInterpreter *
SBCommandInterpreter::get ()
{
@@ -532,7 +562,7 @@ SBCommandInterpreter::GetBroadcaster ()
const char *
SBCommandInterpreter::GetBroadcasterClass ()
{
- return Communication::GetStaticBroadcasterClass().AsCString();
+ return CommandInterpreter::GetStaticBroadcasterClass().AsCString();
}
const char *
@@ -548,6 +578,12 @@ SBCommandInterpreter::GetArgumentDescriptionAsCString (const lldb::CommandArgume
}
bool
+SBCommandInterpreter::EventIsCommandInterpreterEvent (const lldb::SBEvent &event)
+{
+ return event.GetBroadcasterClass() == SBCommandInterpreter::GetBroadcasterClass();
+}
+
+bool
SBCommandInterpreter::SetCommandOverrideCallback (const char *command_name,
lldb::CommandOverrideCallback callback,
void *baton)
@@ -566,170 +602,6 @@ SBCommandInterpreter::SetCommandOverrideCallback (const char *command_name,
return false;
}
-#ifndef LLDB_DISABLE_PYTHON
-
-// Defined in the SWIG source file
-extern "C" void
-init_lldb(void);
-
-// these are the Pythonic implementations of the required callbacks
-// these are scripting-language specific, which is why they belong here
-// we still need to use function pointers to them instead of relying
-// on linkage-time resolution because the SWIG stuff and this file
-// get built at different times
-extern "C" bool
-LLDBSwigPythonBreakpointCallbackFunction (const char *python_function_name,
- const char *session_dictionary_name,
- const lldb::StackFrameSP& sb_frame,
- const lldb::BreakpointLocationSP& sb_bp_loc);
-
-extern "C" bool
-LLDBSwigPythonWatchpointCallbackFunction (const char *python_function_name,
- const char *session_dictionary_name,
- const lldb::StackFrameSP& sb_frame,
- const lldb::WatchpointSP& sb_wp);
-
-extern "C" bool
-LLDBSwigPythonCallTypeScript (const char *python_function_name,
- void *session_dictionary,
- const lldb::ValueObjectSP& valobj_sp,
- void** pyfunct_wrapper,
- const lldb::TypeSummaryOptionsSP& options_sp,
- std::string& retval);
-
-extern "C" void*
-LLDBSwigPythonCreateSyntheticProvider (const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::ValueObjectSP& valobj_sp);
-
-
-extern "C" void*
-LLDBSwigPythonCreateScriptedThreadPlan (const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::ThreadPlanSP& thread_plan_sp);
-
-extern "C" bool
-LLDBSWIGPythonCallThreadPlan (void *implementor,
- const char *method_name,
- Event *event_sp,
- bool &got_error);
-
-extern "C" uint32_t
-LLDBSwigPython_CalculateNumChildren (void *implementor);
-
-extern "C" void *
-LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx);
-
-extern "C" int
-LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name);
-
-extern "C" void *
-LLDBSWIGPython_CastPyObjectToSBValue (void* data);
-
-extern lldb::ValueObjectSP
-LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data);
-
-extern "C" bool
-LLDBSwigPython_UpdateSynthProviderInstance (void* implementor);
-
-extern "C" bool
-LLDBSwigPython_MightHaveChildrenSynthProviderInstance (void* implementor);
-
-extern "C" void *
-LLDBSwigPython_GetValueSynthProviderInstance (void* implementor);
-
-extern "C" bool
-LLDBSwigPythonCallCommand (const char *python_function_name,
- const char *session_dictionary_name,
- lldb::DebuggerSP& debugger,
- const char* args,
- lldb_private::CommandReturnObject &cmd_retobj,
- lldb::ExecutionContextRefSP exe_ctx_ref_sp);
-
-extern "C" bool
-LLDBSwigPythonCallModuleInit (const char *python_module_name,
- const char *session_dictionary_name,
- lldb::DebuggerSP& debugger);
-
-extern "C" void*
-LLDBSWIGPythonCreateOSPlugin (const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::ProcessSP& process_sp);
-
-extern "C" bool
-LLDBSWIGPythonRunScriptKeywordProcess (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::ProcessSP& process,
- std::string& output);
-
-extern "C" bool
-LLDBSWIGPythonRunScriptKeywordThread (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::ThreadSP& thread,
- std::string& output);
-
-extern "C" bool
-LLDBSWIGPythonRunScriptKeywordTarget (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::TargetSP& target,
- std::string& output);
-
-extern "C" bool
-LLDBSWIGPythonRunScriptKeywordFrame (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::StackFrameSP& frame,
- std::string& output);
-
-extern "C" bool
-LLDBSWIGPythonRunScriptKeywordValue (const char* python_function_name,
- const char* session_dictionary_name,
- lldb::ValueObjectSP& value,
- std::string& output);
-
-extern "C" void*
-LLDBSWIGPython_GetDynamicSetting (void* module,
- const char* setting,
- const lldb::TargetSP& target_sp);
-
-
-#endif
-
-void
-SBCommandInterpreter::InitializeSWIG ()
-{
- static bool g_initialized = false;
- if (!g_initialized)
- {
- g_initialized = true;
-#ifndef LLDB_DISABLE_PYTHON
- ScriptInterpreter::InitializeInterpreter (init_lldb,
- LLDBSwigPythonBreakpointCallbackFunction,
- LLDBSwigPythonWatchpointCallbackFunction,
- LLDBSwigPythonCallTypeScript,
- LLDBSwigPythonCreateSyntheticProvider,
- LLDBSwigPython_CalculateNumChildren,
- LLDBSwigPython_GetChildAtIndex,
- LLDBSwigPython_GetIndexOfChildWithName,
- LLDBSWIGPython_CastPyObjectToSBValue,
- LLDBSWIGPython_GetValueObjectSPFromSBValue,
- LLDBSwigPython_UpdateSynthProviderInstance,
- LLDBSwigPython_MightHaveChildrenSynthProviderInstance,
- LLDBSwigPython_GetValueSynthProviderInstance,
- LLDBSwigPythonCallCommand,
- LLDBSwigPythonCallModuleInit,
- LLDBSWIGPythonCreateOSPlugin,
- LLDBSWIGPythonRunScriptKeywordProcess,
- LLDBSWIGPythonRunScriptKeywordThread,
- LLDBSWIGPythonRunScriptKeywordTarget,
- LLDBSWIGPythonRunScriptKeywordFrame,
- LLDBSWIGPythonRunScriptKeywordValue,
- LLDBSWIGPython_GetDynamicSetting,
- LLDBSwigPythonCreateScriptedThreadPlan,
- LLDBSWIGPythonCallThreadPlan);
-#endif
- }
-}
-
lldb::SBCommand
SBCommandInterpreter::AddMultiwordCommand (const char* name, const char* help)
{
@@ -780,6 +652,28 @@ SBCommand::GetHelp ()
return NULL;
}
+const char*
+SBCommand::GetHelpLong ()
+{
+ if (IsValid ())
+ return m_opaque_sp->GetHelpLong ();
+ return NULL;
+}
+
+void
+SBCommand::SetHelp (const char* help)
+{
+ if (IsValid())
+ m_opaque_sp->SetHelp(help);
+}
+
+void
+SBCommand::SetHelpLong (const char* help)
+{
+ if (IsValid())
+ m_opaque_sp->SetHelpLong(help);
+}
+
lldb::SBCommand
SBCommand::AddMultiwordCommand (const char* name, const char* help)
{
@@ -809,3 +703,17 @@ SBCommand::AddCommand (const char* name, lldb::SBCommandPluginInterface *impl, c
return lldb::SBCommand();
}
+uint32_t
+SBCommand::GetFlags ()
+{
+ if (!IsValid())
+ return 0;
+ return m_opaque_sp->GetFlags().Get();
+}
+
+void
+SBCommand::SetFlags (uint32_t flags)
+{
+ if (IsValid())
+ m_opaque_sp->GetFlags().Set(flags);
+}
diff --git a/source/API/SBDebugger.cpp b/source/API/SBDebugger.cpp
index a95f2ffc06d9..df2019f5a46b 100644
--- a/source/API/SBDebugger.cpp
+++ b/source/API/SBDebugger.cpp
@@ -7,12 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBDebugger.h"
#include "lldb/lldb-private.h"
+#include "lldb/API/SystemInitializerFull.h"
#include "lldb/API/SBListener.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBCommandInterpreter.h"
@@ -33,46 +32,24 @@
#include "lldb/API/SBTypeSummary.h"
#include "lldb/API/SBTypeSynthetic.h"
-
#include "lldb/Core/Debugger.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Initialization/SystemLifetimeManager.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/OptionGroupPlatform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/TargetList.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/DynamicLibrary.h"
using namespace lldb;
using namespace lldb_private;
-SBInputReader::SBInputReader()
-{
-}
-SBInputReader::~SBInputReader()
-{
-}
-
-SBError
-SBInputReader::Initialize(lldb::SBDebugger& sb_debugger, unsigned long (*)(void*, lldb::SBInputReader*, lldb::InputReaderAction, char const*, unsigned long), void*, lldb::InputReaderGranularity, char const*, char const*, bool)
-{
- return SBError();
-}
-
-void
-SBInputReader::SetIsDone(bool)
-{
-}
-bool
-SBInputReader::IsActive() const
-{
- return false;
-}
-
static llvm::sys::DynamicLibrary
LoadPlugin (const lldb::DebuggerSP &debugger_sp, const FileSpec& spec, Error& error)
{
@@ -107,6 +84,34 @@ LoadPlugin (const lldb::DebuggerSP &debugger_sp, const FileSpec& spec, Error& er
return llvm::sys::DynamicLibrary();
}
+static llvm::ManagedStatic<SystemLifetimeManager> g_debugger_lifetime;
+
+SBInputReader::SBInputReader()
+{
+}
+SBInputReader::~SBInputReader()
+{
+}
+
+SBError
+SBInputReader::Initialize(lldb::SBDebugger &sb_debugger,
+ unsigned long (*)(void *, lldb::SBInputReader *, lldb::InputReaderAction, char const *,
+ unsigned long),
+ void *, lldb::InputReaderGranularity, char const *, char const *, bool)
+{
+ return SBError();
+}
+
+void
+SBInputReader::SetIsDone(bool)
+{
+}
+bool
+SBInputReader::IsActive() const
+{
+ return false;
+}
+
void
SBDebugger::Initialize ()
{
@@ -115,15 +120,13 @@ SBDebugger::Initialize ()
if (log)
log->Printf ("SBDebugger::Initialize ()");
- SBCommandInterpreter::InitializeSWIG ();
-
- Debugger::Initialize(LoadPlugin);
+ g_debugger_lifetime->Initialize(llvm::make_unique<SystemInitializerFull>(), LoadPlugin);
}
void
SBDebugger::Terminate ()
{
- Debugger::Terminate();
+ g_debugger_lifetime->Terminate();
}
void
diff --git a/source/API/SBEvent.cpp b/source/API/SBEvent.cpp
index c62c495b87c8..164636defc9a 100644
--- a/source/API/SBEvent.cpp
+++ b/source/API/SBEvent.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBEvent.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBExpressionOptions.cpp b/source/API/SBExpressionOptions.cpp
index 448ff4cf6dd6..43b7d03064f5 100644
--- a/source/API/SBExpressionOptions.cpp
+++ b/source/API/SBExpressionOptions.cpp
@@ -185,6 +185,17 @@ SBExpressionOptions::SetSuppressPersistentResult (bool b)
return m_opaque_ap->SetResultIsInternal (b);
}
+const char *
+SBExpressionOptions::GetPrefix () const
+{
+ return m_opaque_ap->GetPrefix();
+}
+
+void
+SBExpressionOptions::SetPrefix (const char *prefix)
+{
+ return m_opaque_ap->SetPrefix(prefix);
+}
EvaluateExpressionOptions *
SBExpressionOptions::get() const
diff --git a/source/API/SBFileSpec.cpp b/source/API/SBFileSpec.cpp
index 8d63fc587d81..dd7435de1b5b 100644
--- a/source/API/SBFileSpec.cpp
+++ b/source/API/SBFileSpec.cpp
@@ -93,9 +93,8 @@ SBFileSpec::ResolvePath (const char *src_path, char *dst_path, size_t dst_len)
{
llvm::SmallString<64> result(src_path);
lldb_private::FileSpec::Resolve (result);
- size_t result_length = std::min(dst_len-1, result.size());
- ::strncpy(dst_path, result.c_str(), result_length + 1);
- return result_length;
+ ::snprintf(dst_path, dst_len, "%s", result.c_str());
+ return std::min(dst_len-1, result.size());
}
const char *
@@ -120,18 +119,19 @@ SBFileSpec::GetFilename() const
const char *
SBFileSpec::GetDirectory() const
{
- const char *s = m_opaque_ap->GetDirectory().AsCString();
+ FileSpec directory{*m_opaque_ap};
+ directory.GetFilename().Clear();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
{
- if (s)
+ if (directory)
log->Printf ("SBFileSpec(%p)::GetDirectory () => \"%s\"",
- static_cast<void*>(m_opaque_ap.get()), s);
+ static_cast<void*>(m_opaque_ap.get()), directory.GetCString());
else
log->Printf ("SBFileSpec(%p)::GetDirectory () => NULL",
static_cast<void*>(m_opaque_ap.get()));
}
- return s;
+ return directory.GetCString();
}
void
diff --git a/source/API/SBFrame.cpp b/source/API/SBFrame.cpp
index 325f40fd5b56..e845aef41f45 100644
--- a/source/API/SBFrame.cpp
+++ b/source/API/SBFrame.cpp
@@ -21,6 +21,7 @@
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObjectRegister.h"
#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
#include "lldb/Expression/ClangUserExpression.h"
#include "lldb/Host/Host.h"
#include "lldb/Symbol/Block.h"
@@ -44,6 +45,7 @@
#include "lldb/API/SBStream.h"
#include "lldb/API/SBSymbolContext.h"
#include "lldb/API/SBThread.h"
+#include "lldb/API/SBVariablesOptions.h"
using namespace lldb;
using namespace lldb_private;
@@ -452,6 +454,17 @@ SBFrame::GetFrameID () const
return frame_idx;
}
+lldb::addr_t
+SBFrame::GetCFA () const
+{
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame)
+ return frame->GetStackID().GetCallFrameAddress();
+ return LLDB_INVALID_ADDRESS;
+}
+
+
addr_t
SBFrame::GetPC () const
{
@@ -868,32 +881,30 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy
case eValueTypeVariableArgument: // function argument variables
case eValueTypeVariableLocal: // function local variables
{
- SymbolContext sc (frame->GetSymbolContext (eSymbolContextBlock));
+ SymbolContext sc(frame->GetSymbolContext(eSymbolContextBlock));
const bool can_create = true;
const bool get_parent_variables = true;
const bool stop_if_block_is_inlined_function = true;
- if (sc.block && sc.block->AppendVariables (can_create,
- get_parent_variables,
- stop_if_block_is_inlined_function,
- &variable_list))
+ if (sc.block)
+ sc.block->AppendVariables(can_create,
+ get_parent_variables,
+ stop_if_block_is_inlined_function,
+ &variable_list);
+ if (value_type == eValueTypeVariableGlobal)
{
- if (value_type == eValueTypeVariableGlobal)
- {
- const bool get_file_globals = true;
- VariableList* frame_vars = frame->GetVariableList(get_file_globals);
- if (frame_vars)
- frame_vars->AppendVariablesIfUnique(variable_list);
- }
- ConstString const_name(name);
- VariableSP variable_sp(variable_list.FindVariable(const_name,value_type));
- if (variable_sp)
- {
- value_sp = frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues);
- sb_value.SetSP (value_sp, use_dynamic);
- break;
- }
+ const bool get_file_globals = true;
+ VariableList *frame_vars = frame->GetVariableList(get_file_globals);
+ if (frame_vars)
+ frame_vars->AppendVariablesIfUnique(variable_list);
+ }
+ ConstString const_name(name);
+ VariableSP variable_sp(variable_list.FindVariable(const_name, value_type));
+ if (variable_sp)
+ {
+ value_sp = frame->GetValueObjectForFrameVariable(variable_sp, eNoDynamicValues);
+ sb_value.SetSP(value_sp, use_dynamic);
}
}
break;
@@ -1075,18 +1086,44 @@ SBFrame::GetVariables (bool arguments,
if (frame && target)
{
lldb::DynamicValueType use_dynamic = frame->CalculateTarget()->GetPreferDynamicValue();
- value_list = GetVariables (arguments, locals, statics, in_scope_only, use_dynamic);
+ const bool include_runtime_support_values = target ? target->GetDisplayRuntimeSupportValues() : false;
+
+ SBVariablesOptions options;
+ options.SetIncludeArguments(arguments);
+ options.SetIncludeLocals(locals);
+ options.SetIncludeStatics(statics);
+ options.SetInScopeOnly(in_scope_only);
+ options.SetIncludeRuntimeSupportValues(include_runtime_support_values);
+ options.SetUseDynamic(use_dynamic);
+
+ value_list = GetVariables (options);
}
return value_list;
}
-SBValueList
+lldb::SBValueList
SBFrame::GetVariables (bool arguments,
bool locals,
bool statics,
bool in_scope_only,
lldb::DynamicValueType use_dynamic)
{
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ Target *target = exe_ctx.GetTargetPtr();
+ const bool include_runtime_support_values = target ? target->GetDisplayRuntimeSupportValues() : false;
+ SBVariablesOptions options;
+ options.SetIncludeArguments(arguments);
+ options.SetIncludeLocals(locals);
+ options.SetIncludeStatics(statics);
+ options.SetInScopeOnly(in_scope_only);
+ options.SetIncludeRuntimeSupportValues(include_runtime_support_values);
+ options.SetUseDynamic(use_dynamic);
+ return GetVariables(options);
+}
+
+SBValueList
+SBFrame::GetVariables (const lldb::SBVariablesOptions& options)
+{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBValueList value_list;
@@ -1096,10 +1133,19 @@ SBFrame::GetVariables (bool arguments,
StackFrame *frame = NULL;
Target *target = exe_ctx.GetTargetPtr();
+ const bool statics = options.GetIncludeStatics();
+ const bool arguments = options.GetIncludeArguments();
+ const bool locals = options.GetIncludeLocals();
+ const bool in_scope_only = options.GetInScopeOnly();
+ const bool include_runtime_support_values = options.GetIncludeRuntimeSupportValues();
+ const lldb::DynamicValueType use_dynamic = options.GetUseDynamic();
+
if (log)
- log->Printf ("SBFrame::GetVariables (arguments=%i, locals=%i, statics=%i, in_scope_only=%i)",
- arguments, locals, statics, in_scope_only);
-
+ log->Printf ("SBFrame::GetVariables (arguments=%i, locals=%i, statics=%i, in_scope_only=%i runtime=%i dynamic=%i)",
+ arguments, locals,
+ statics, in_scope_only,
+ include_runtime_support_values, use_dynamic);
+
Process *process = exe_ctx.GetProcessPtr();
if (target && process)
{
@@ -1147,6 +1193,12 @@ SBFrame::GetVariables (bool arguments,
continue;
ValueObjectSP valobj_sp(frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues));
+
+ if (false == include_runtime_support_values &&
+ valobj_sp &&
+ true == valobj_sp->IsRuntimeSupportValue())
+ continue;
+
SBValue value_sb;
value_sb.SetSP(valobj_sp,use_dynamic);
value_list.Append(value_sb);
@@ -1449,6 +1501,12 @@ SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &option
bool
SBFrame::IsInlined()
{
+ return static_cast<const SBFrame*>(this)->IsInlined();
+}
+
+bool
+SBFrame::IsInlined() const
+{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
ExecutionContext exe_ctx(m_opaque_sp.get());
StackFrame *frame = NULL;
@@ -1486,6 +1544,12 @@ SBFrame::IsInlined()
const char *
SBFrame::GetFunctionName()
{
+ return static_cast<const SBFrame*>(this)->GetFunctionName();
+}
+
+const char *
+SBFrame::GetFunctionName() const
+{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
const char *name = NULL;
ExecutionContext exe_ctx(m_opaque_sp.get());
@@ -1538,4 +1602,3 @@ SBFrame::GetFunctionName()
}
return name;
}
-
diff --git a/source/API/SBInstruction.cpp b/source/API/SBInstruction.cpp
index 6158418d2f2a..36be94801863 100644
--- a/source/API/SBInstruction.cpp
+++ b/source/API/SBInstruction.cpp
@@ -180,7 +180,7 @@ SBInstruction::GetDescription (lldb::SBStream &s)
// didn't have a stream already created, one will get created...
FormatEntity::Entry format;
FormatEntity::Parse("${addr}: ", format);
- m_opaque_sp->Dump (&s.ref(), 0, true, false, NULL, &sc, NULL, &format);
+ m_opaque_sp->Dump (&s.ref(), 0, true, false, NULL, &sc, NULL, &format, 0);
return true;
}
return false;
@@ -202,7 +202,7 @@ SBInstruction::Print (FILE *out)
StreamFile out_stream (out, false);
FormatEntity::Entry format;
FormatEntity::Parse("${addr}: ", format);
- m_opaque_sp->Dump (&out_stream, 0, true, false, NULL, &sc, NULL, &format);
+ m_opaque_sp->Dump (&out_stream, 0, true, false, NULL, &sc, NULL, &format, 0);
}
}
diff --git a/source/API/SBInstructionList.cpp b/source/API/SBInstructionList.cpp
index 812824b4d2e5..34b0e05079f8 100644
--- a/source/API/SBInstructionList.cpp
+++ b/source/API/SBInstructionList.cpp
@@ -120,7 +120,7 @@ SBInstructionList::GetDescription (lldb::SBStream &description)
module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
}
- inst->Dump (&sref, max_opcode_byte_size, true, false, NULL, &sc, &prev_sc, &format);
+ inst->Dump (&sref, max_opcode_byte_size, true, false, NULL, &sc, &prev_sc, &format, 0);
sref.EOL();
}
return true;
diff --git a/source/API/SBLanguageRuntime.cpp b/source/API/SBLanguageRuntime.cpp
new file mode 100644
index 000000000000..93a54cd76dff
--- /dev/null
+++ b/source/API/SBLanguageRuntime.cpp
@@ -0,0 +1,26 @@
+//===-- SBLanguageRuntime.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBLanguageRuntime.h"
+#include "lldb/Target/LanguageRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+lldb::LanguageType
+SBLanguageRuntime::GetLanguageTypeFromString (const char *string)
+{
+ return LanguageRuntime::GetLanguageTypeFromString(string);
+}
+
+const char *
+SBLanguageRuntime::GetNameForLanguageType (lldb::LanguageType language)
+{
+ return LanguageRuntime::GetNameForLanguageType(language);
+}
diff --git a/source/API/SBLaunchInfo.cpp b/source/API/SBLaunchInfo.cpp
index dcb0e1b488ba..54bed8799b8b 100644
--- a/source/API/SBLaunchInfo.cpp
+++ b/source/API/SBLaunchInfo.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBLaunchInfo.h"
#include "lldb/API/SBFileSpec.h"
@@ -36,6 +34,12 @@ SBLaunchInfo::ref ()
return *m_opaque_sp;
}
+const lldb_private::ProcessLaunchInfo &
+SBLaunchInfo::ref () const
+{
+ return *m_opaque_sp;
+}
+
lldb::pid_t
SBLaunchInfo::GetProcessID()
{
@@ -169,13 +173,13 @@ SBLaunchInfo::Clear ()
const char *
SBLaunchInfo::GetWorkingDirectory () const
{
- return m_opaque_sp->GetWorkingDirectory();
+ return m_opaque_sp->GetWorkingDirectory().GetCString();
}
void
SBLaunchInfo::SetWorkingDirectory (const char *working_dir)
{
- m_opaque_sp->SetWorkingDirectory(working_dir);
+ m_opaque_sp->SetWorkingDirectory(FileSpec{working_dir, false});
}
uint32_t
@@ -217,6 +221,18 @@ SBLaunchInfo::SetShell (const char * path)
m_opaque_sp->SetShell (FileSpec(path, false));
}
+bool
+SBLaunchInfo::GetShellExpandArguments ()
+{
+ return m_opaque_sp->GetShellExpandArguments();
+}
+
+void
+SBLaunchInfo::SetShellExpandArguments (bool expand)
+{
+ m_opaque_sp->SetShellExpandArguments(expand);
+}
+
uint32_t
SBLaunchInfo::GetResumeCount ()
{
@@ -244,7 +260,7 @@ SBLaunchInfo::AddDuplicateFileAction (int fd, int dup_fd)
bool
SBLaunchInfo::AddOpenFileAction (int fd, const char *path, bool read, bool write)
{
- return m_opaque_sp->AppendOpenFileAction(fd, path, read, write);
+ return m_opaque_sp->AppendOpenFileAction(fd, FileSpec{path, false}, read, write);
}
bool
diff --git a/source/API/SBListener.cpp b/source/API/SBListener.cpp
index 87318739a3a4..643c82d70f78 100644
--- a/source/API/SBListener.cpp
+++ b/source/API/SBListener.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBListener.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBDebugger.h"
diff --git a/source/API/SBModule.cpp b/source/API/SBModule.cpp
index 0d7dda1aa1f7..0249a7edcd2b 100644
--- a/source/API/SBModule.cpp
+++ b/source/API/SBModule.cpp
@@ -20,6 +20,7 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectList.h"
#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/Symtab.h"
@@ -211,34 +212,28 @@ SBModule::GetUUIDString () const
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
- static char uuid_string_buffer[80];
- const char *uuid_c_string = NULL;
- std::string uuid_string;
+ const char *uuid_cstr = NULL;
ModuleSP module_sp (GetSP ());
if (module_sp)
- uuid_string = module_sp->GetUUID().GetAsString();
-
- if (!uuid_string.empty())
{
- strncpy (uuid_string_buffer, uuid_string.c_str(), sizeof (uuid_string_buffer));
- uuid_string_buffer[sizeof (uuid_string_buffer) - 1] = '\0';
- uuid_c_string = uuid_string_buffer;
+ // We are going to return a "const char *" value through the public
+ // API, so we need to constify it so it gets added permanently the
+ // string pool and then we don't need to worry about the lifetime of the
+ // string as it will never go away once it has been put into the ConstString
+ // string pool
+ uuid_cstr = ConstString(module_sp->GetUUID().GetAsString()).GetCString();
}
- if (log)
+ if (uuid_cstr && uuid_cstr[0])
{
- if (!uuid_string.empty())
- {
- StreamString s;
- module_sp->GetUUID().Dump (&s);
- log->Printf ("SBModule(%p)::GetUUIDString () => %s",
- static_cast<void*>(module_sp.get()), s.GetData());
- }
- else
- log->Printf ("SBModule(%p)::GetUUIDString () => NULL",
- static_cast<void*>(module_sp.get()));
+ if (log)
+ log->Printf ("SBModule(%p)::GetUUIDString () => %s", static_cast<void*>(module_sp.get()), uuid_cstr);
+ return uuid_cstr;
}
- return uuid_c_string;
+
+ if (log)
+ log->Printf ("SBModule(%p)::GetUUIDString () => NULL", static_cast<void*>(module_sp.get()));
+ return NULL;
}
@@ -690,3 +685,30 @@ SBModule::GetVersion (uint32_t *versions, uint32_t num_versions)
}
}
+lldb::SBFileSpec
+SBModule::GetSymbolFileSpec() const
+{
+ lldb::SBFileSpec sb_file_spec;
+ ModuleSP module_sp(GetSP());
+ if (module_sp)
+ {
+ SymbolVendor *symbol_vendor_ptr = module_sp->GetSymbolVendor();
+ if (symbol_vendor_ptr)
+ sb_file_spec.SetFileSpec(symbol_vendor_ptr->GetMainFileSpec());
+ }
+ return sb_file_spec;
+}
+
+lldb::SBAddress
+SBModule::GetObjectFileHeaderAddress() const
+{
+ lldb::SBAddress sb_addr;
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ ObjectFile *objfile_ptr = module_sp->GetObjectFile();
+ if (objfile_ptr)
+ sb_addr.ref() = objfile_ptr->GetHeaderAddress();
+ }
+ return sb_addr;
+}
diff --git a/source/API/SBPlatform.cpp b/source/API/SBPlatform.cpp
index b23891d39c21..5662f36b514d 100644
--- a/source/API/SBPlatform.cpp
+++ b/source/API/SBPlatform.cpp
@@ -329,9 +329,9 @@ SBPlatform::SetWorkingDirectory(const char *path)
if (platform_sp)
{
if (path)
- platform_sp->SetWorkingDirectory(ConstString(path));
+ platform_sp->SetWorkingDirectory(FileSpec{path, false});
else
- platform_sp->SetWorkingDirectory(ConstString());
+ platform_sp->SetWorkingDirectory(FileSpec{});
return true;
}
return false;
@@ -378,7 +378,7 @@ SBPlatform::GetTriple()
PlatformSP platform_sp(GetSP());
if (platform_sp)
{
- ArchSpec arch(platform_sp->GetRemoteSystemArchitecture());
+ ArchSpec arch(platform_sp->GetSystemArchitecture());
if (arch.IsValid())
{
// Const-ify the string so we don't need to worry about the lifetime of the string
@@ -545,7 +545,7 @@ SBPlatform::Run (SBPlatformShellCommand &shell_command)
shell_command.SetWorkingDirectory(working_dir);
}
return platform_sp->RunShellCommand(command,
- working_dir,
+ FileSpec{working_dir, false},
&shell_command.m_opaque_ptr->m_status,
&shell_command.m_opaque_ptr->m_signo,
&shell_command.m_opaque_ptr->m_output,
@@ -598,7 +598,7 @@ SBPlatform::MakeDirectory (const char *path, uint32_t file_permissions)
PlatformSP platform_sp(GetSP());
if (platform_sp)
{
- sb_error.ref() = platform_sp->MakeDirectory(path, file_permissions);
+ sb_error.ref() = platform_sp->MakeDirectory(FileSpec{path, false}, file_permissions);
}
else
{
@@ -614,7 +614,7 @@ SBPlatform::GetFilePermissions (const char *path)
if (platform_sp)
{
uint32_t file_permissions = 0;
- platform_sp->GetFilePermissions(path, file_permissions);
+ platform_sp->GetFilePermissions(FileSpec{path, false}, file_permissions);
return file_permissions;
}
return 0;
@@ -628,7 +628,7 @@ SBPlatform::SetFilePermissions (const char *path, uint32_t file_permissions)
PlatformSP platform_sp(GetSP());
if (platform_sp)
{
- sb_error.ref() = platform_sp->SetFilePermissions(path, file_permissions);
+ sb_error.ref() = platform_sp->SetFilePermissions(FileSpec{path, false}, file_permissions);
}
else
{
diff --git a/source/API/SBProcess.cpp b/source/API/SBProcess.cpp
index 9a0b23bc93d2..a1dbf686da03 100644
--- a/source/API/SBProcess.cpp
+++ b/source/API/SBProcess.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBProcess.h"
// C Includes
@@ -169,11 +167,11 @@ SBProcess::RemoteLaunch (char const **argv,
{
if (stop_at_entry)
launch_flags |= eLaunchFlagStopAtEntry;
- ProcessLaunchInfo launch_info (stdin_path,
- stdout_path,
- stderr_path,
- working_directory,
- launch_flags);
+ ProcessLaunchInfo launch_info(FileSpec{stdin_path, false},
+ FileSpec{stdout_path, false},
+ FileSpec{stderr_path, false},
+ FileSpec{working_directory, false},
+ launch_flags);
Module *exe_module = process_sp->GetTarget().GetExecutableModulePointer();
if (exe_module)
launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
@@ -603,6 +601,30 @@ SBProcess::GetStopID(bool include_expression_stops)
return 0;
}
+SBEvent
+SBProcess::GetStopEventForStopID(uint32_t stop_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBEvent sb_event;
+ EventSP event_sp;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ event_sp = process_sp->GetStopEventForStopID(stop_id);
+ sb_event.reset(event_sp);
+ }
+
+ if (log)
+ log->Printf ("SBProcess(%p)::GetStopEventForStopID (stop_id=%" PRIu32 ") => SBEvent(%p)",
+ static_cast<void*>(process_sp.get()),
+ stop_id,
+ static_cast<void*>(event_sp.get()));
+
+ return sb_event;
+}
+
StateType
SBProcess::GetState ()
{
@@ -768,7 +790,7 @@ SBProcess::Destroy ()
if (process_sp)
{
Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
- sb_error.SetError(process_sp->Destroy());
+ sb_error.SetError(process_sp->Destroy(false));
}
else
sb_error.SetErrorString ("SBProcess is invalid");
@@ -821,7 +843,7 @@ SBProcess::Kill ()
if (process_sp)
{
Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
- sb_error.SetError (process_sp->Destroy());
+ sb_error.SetError (process_sp->Destroy(true));
}
else
sb_error.SetErrorString ("SBProcess is invalid");
@@ -918,9 +940,9 @@ SBProcess::GetThreadByID (tid_t tid)
ProcessSP process_sp(GetSP());
if (process_sp)
{
- Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
Process::StopLocker stop_locker;
const bool can_update = stop_locker.TryLock(&process_sp->GetRunLock());
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
thread_sp = process_sp->GetThreadList().FindThreadByID (tid, can_update);
sb_thread.SetThread (thread_sp);
}
@@ -942,9 +964,9 @@ SBProcess::GetThreadByIndexID (uint32_t index_id)
ProcessSP process_sp(GetSP());
if (process_sp)
{
- Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
Process::StopLocker stop_locker;
const bool can_update = stop_locker.TryLock(&process_sp->GetRunLock());
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
thread_sp = process_sp->GetThreadList().FindThreadByIndexID (index_id, can_update);
sb_thread.SetThread (thread_sp);
}
@@ -999,9 +1021,15 @@ SBProcess::GetProcessFromEvent (const SBEvent &event)
}
bool
+SBProcess::GetInterruptedFromEvent (const SBEvent &event)
+{
+ return Process::ProcessEventData::GetInterruptedFromEvent(event.get());
+}
+
+bool
SBProcess::EventIsProcessEvent (const SBEvent &event)
{
- return strcmp (event.GetBroadcasterClass(), SBProcess::GetBroadcasterClass()) == 0;
+ return event.GetBroadcasterClass() == SBProcess::GetBroadcasterClass();
}
SBBroadcaster
diff --git a/source/API/SBQueue.cpp b/source/API/SBQueue.cpp
index b19ed72543c2..be4c5fda1540 100644
--- a/source/API/SBQueue.cpp
+++ b/source/API/SBQueue.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include <inttypes.h>
#include "lldb/API/SBQueue.h"
diff --git a/source/API/SBQueueItem.cpp b/source/API/SBQueueItem.cpp
index 6a1aa7bec61a..e7a199b9f0b4 100644
--- a/source/API/SBQueueItem.cpp
+++ b/source/API/SBQueueItem.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
#include "lldb/lldb-forward.h"
#include "lldb/API/SBAddress.h"
diff --git a/source/API/SBSourceManager.cpp b/source/API/SBSourceManager.cpp
index 0b8cbfceda0f..8196b91d00b3 100644
--- a/source/API/SBSourceManager.cpp
+++ b/source/API/SBSourceManager.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBSourceManager.h"
#include "lldb/API/SBTarget.h"
diff --git a/source/API/SBSymbol.cpp b/source/API/SBSymbol.cpp
index 12a3b317d501..246a455d93a7 100644
--- a/source/API/SBSymbol.cpp
+++ b/source/API/SBSymbol.cpp
@@ -137,10 +137,11 @@ SBSymbol::GetInstructions (SBTarget target, const char *flavor_string)
}
if (m_opaque_ptr->ValueIsAddress())
{
- ModuleSP module_sp (m_opaque_ptr->GetAddress().GetModule());
+ const Address &symbol_addr = m_opaque_ptr->GetAddressRef();
+ ModuleSP module_sp = symbol_addr.GetModule();
if (module_sp)
{
- AddressRange symbol_range (m_opaque_ptr->GetAddress(), m_opaque_ptr->GetByteSize());
+ AddressRange symbol_range (symbol_addr, m_opaque_ptr->GetByteSize());
const bool prefer_file_cache = false;
sb_instructions.SetDisassembler (Disassembler::DisassembleRange (module_sp->GetArchitecture (),
NULL,
@@ -172,7 +173,7 @@ SBSymbol::GetStartAddress ()
SBAddress addr;
if (m_opaque_ptr && m_opaque_ptr->ValueIsAddress())
{
- addr.SetAddress (&m_opaque_ptr->GetAddress());
+ addr.SetAddress (&m_opaque_ptr->GetAddressRef());
}
return addr;
}
@@ -186,7 +187,7 @@ SBSymbol::GetEndAddress ()
lldb::addr_t range_size = m_opaque_ptr->GetByteSize();
if (range_size > 0)
{
- addr.SetAddress (&m_opaque_ptr->GetAddress());
+ addr.SetAddress (&m_opaque_ptr->GetAddressRef());
addr->Slide (m_opaque_ptr->GetByteSize());
}
}
diff --git a/source/API/SBTarget.cpp b/source/API/SBTarget.cpp
index b13d8289560f..923885223a5f 100644
--- a/source/API/SBTarget.cpp
+++ b/source/API/SBTarget.cpp
@@ -7,14 +7,13 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTarget.h"
#include "lldb/lldb-public.h"
-#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBBreakpoint.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBEvent.h"
#include "lldb/API/SBExpressionOptions.h"
#include "lldb/API/SBFileSpec.h"
#include "lldb/API/SBListener.h"
@@ -47,12 +46,16 @@
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/DeclVendor.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
-
+#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
@@ -66,230 +69,31 @@ using namespace lldb_private;
#define DEFAULT_DISASM_BYTE_SIZE 32
+namespace {
-SBAttachInfo::SBAttachInfo () :
- m_opaque_sp (new ProcessAttachInfo())
-{
-}
-
-SBAttachInfo::SBAttachInfo (lldb::pid_t pid) :
- m_opaque_sp (new ProcessAttachInfo())
-{
- m_opaque_sp->SetProcessID (pid);
-}
-
-SBAttachInfo::SBAttachInfo (const char *path, bool wait_for) :
- m_opaque_sp (new ProcessAttachInfo())
-{
- if (path && path[0])
- m_opaque_sp->GetExecutableFile().SetFile(path, false);
- m_opaque_sp->SetWaitForLaunch (wait_for);
-}
-
-SBAttachInfo::SBAttachInfo (const SBAttachInfo &rhs) :
- m_opaque_sp (new ProcessAttachInfo())
-{
- *m_opaque_sp = *rhs.m_opaque_sp;
-}
-
-SBAttachInfo::~SBAttachInfo()
-{
-}
-
-lldb_private::ProcessAttachInfo &
-SBAttachInfo::ref ()
-{
- return *m_opaque_sp;
-}
-
-SBAttachInfo &
-SBAttachInfo::operator = (const SBAttachInfo &rhs)
-{
- if (this != &rhs)
- *m_opaque_sp = *rhs.m_opaque_sp;
- return *this;
-}
-
-lldb::pid_t
-SBAttachInfo::GetProcessID ()
-{
- return m_opaque_sp->GetProcessID();
-}
-
-void
-SBAttachInfo::SetProcessID (lldb::pid_t pid)
-{
- m_opaque_sp->SetProcessID (pid);
-}
-
-
-uint32_t
-SBAttachInfo::GetResumeCount ()
-{
- return m_opaque_sp->GetResumeCount();
-}
-
-void
-SBAttachInfo::SetResumeCount (uint32_t c)
-{
- m_opaque_sp->SetResumeCount (c);
-}
-
-const char *
-SBAttachInfo::GetProcessPluginName ()
-{
- return m_opaque_sp->GetProcessPluginName();
-}
-
-void
-SBAttachInfo::SetProcessPluginName (const char *plugin_name)
-{
- return m_opaque_sp->SetProcessPluginName (plugin_name);
-}
-
-void
-SBAttachInfo::SetExecutable (const char *path)
-{
- if (path && path[0])
- m_opaque_sp->GetExecutableFile().SetFile(path, false);
- else
- m_opaque_sp->GetExecutableFile().Clear();
-}
-
-void
-SBAttachInfo::SetExecutable (SBFileSpec exe_file)
-{
- if (exe_file.IsValid())
- m_opaque_sp->GetExecutableFile() = exe_file.ref();
- else
- m_opaque_sp->GetExecutableFile().Clear();
-}
-
-bool
-SBAttachInfo::GetWaitForLaunch ()
-{
- return m_opaque_sp->GetWaitForLaunch();
-}
-
-void
-SBAttachInfo::SetWaitForLaunch (bool b)
-{
- m_opaque_sp->SetWaitForLaunch (b);
-}
-
-bool
-SBAttachInfo::GetIgnoreExisting ()
-{
- return m_opaque_sp->GetIgnoreExisting();
-}
-
-void
-SBAttachInfo::SetIgnoreExisting (bool b)
-{
- m_opaque_sp->SetIgnoreExisting (b);
-}
-
-uint32_t
-SBAttachInfo::GetUserID()
-{
- return m_opaque_sp->GetUserID();
-}
-
-uint32_t
-SBAttachInfo::GetGroupID()
-{
- return m_opaque_sp->GetGroupID();
-}
-
-bool
-SBAttachInfo::UserIDIsValid ()
-{
- return m_opaque_sp->UserIDIsValid();
-}
-
-bool
-SBAttachInfo::GroupIDIsValid ()
-{
- return m_opaque_sp->GroupIDIsValid();
-}
-
-void
-SBAttachInfo::SetUserID (uint32_t uid)
-{
- m_opaque_sp->SetUserID (uid);
-}
-
-void
-SBAttachInfo::SetGroupID (uint32_t gid)
-{
- m_opaque_sp->SetGroupID (gid);
-}
-
-uint32_t
-SBAttachInfo::GetEffectiveUserID()
-{
- return m_opaque_sp->GetEffectiveUserID();
-}
-
-uint32_t
-SBAttachInfo::GetEffectiveGroupID()
-{
- return m_opaque_sp->GetEffectiveGroupID();
-}
-
-bool
-SBAttachInfo::EffectiveUserIDIsValid ()
-{
- return m_opaque_sp->EffectiveUserIDIsValid();
-}
-
-bool
-SBAttachInfo::EffectiveGroupIDIsValid ()
-{
- return m_opaque_sp->EffectiveGroupIDIsValid ();
-}
-
-void
-SBAttachInfo::SetEffectiveUserID (uint32_t uid)
-{
- m_opaque_sp->SetEffectiveUserID(uid);
-}
-
-void
-SBAttachInfo::SetEffectiveGroupID (uint32_t gid)
-{
- m_opaque_sp->SetEffectiveGroupID(gid);
-}
-
-lldb::pid_t
-SBAttachInfo::GetParentProcessID ()
-{
- return m_opaque_sp->GetParentProcessID();
-}
-
-void
-SBAttachInfo::SetParentProcessID (lldb::pid_t pid)
+Error
+AttachToProcess (ProcessAttachInfo &attach_info, Target &target)
{
- m_opaque_sp->SetParentProcessID (pid);
-}
+ Mutex::Locker api_locker (target.GetAPIMutex ());
-bool
-SBAttachInfo::ParentProcessIDIsValid()
-{
- return m_opaque_sp->ParentProcessIDIsValid();
-}
+ auto process_sp = target.GetProcessSP ();
+ if (process_sp)
+ {
+ const auto state = process_sp->GetState ();
+ if (process_sp->IsAlive () && state == eStateConnected)
+ {
+ // If we are already connected, then we have already specified the
+ // listener, so if a valid listener is supplied, we need to error out
+ // to let the client know.
+ if (attach_info.GetListener ())
+ return Error ("process is connected and already has a listener, pass empty listener");
+ }
+ }
-SBListener
-SBAttachInfo::GetListener ()
-{
- return SBListener(m_opaque_sp->GetListener());
+ return target.Attach (attach_info, nullptr);
}
-void
-SBAttachInfo::SetListener (SBListener &listener)
-{
- m_opaque_sp->SetListener(listener.GetSP());
-}
+} // namespace
//----------------------------------------------------------------------
// SBTarget constructor
@@ -324,6 +128,32 @@ SBTarget::~SBTarget()
{
}
+bool
+SBTarget::EventIsTargetEvent (const SBEvent &event)
+{
+ return Target::TargetEventData::GetEventDataFromEvent(event.get()) != NULL;
+}
+
+SBTarget
+SBTarget::GetTargetFromEvent (const SBEvent &event)
+{
+ return Target::TargetEventData::GetTargetFromEvent (event.get());
+}
+
+uint32_t
+SBTarget::GetNumModulesFromEvent (const SBEvent &event)
+{
+ const ModuleList module_list = Target::TargetEventData::GetModuleListFromEvent (event.get());
+ return module_list.GetSize();
+}
+
+SBModule
+SBTarget::GetModuleAtIndexFromEvent (const uint32_t idx, const SBEvent &event)
+{
+ const ModuleList module_list = Target::TargetEventData::GetModuleListFromEvent (event.get());
+ return SBModule(module_list.GetModuleAtIndex(idx));
+}
+
const char *
SBTarget::GetBroadcasterClassName ()
{
@@ -513,7 +343,11 @@ SBTarget::Launch
if (getenv("LLDB_LAUNCH_FLAG_DISABLE_STDIO"))
launch_flags |= eLaunchFlagDisableSTDIO;
- ProcessLaunchInfo launch_info (stdin_path, stdout_path, stderr_path, working_directory, launch_flags);
+ ProcessLaunchInfo launch_info(FileSpec{stdin_path, false},
+ FileSpec{stdout_path, false},
+ FileSpec{stderr_path, false},
+ FileSpec{working_directory, false},
+ launch_flags);
Module *exe_module = target_sp->GetExecutableModulePointer();
if (exe_module)
@@ -613,7 +447,6 @@ SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBProcess sb_process;
- ProcessSP process_sp;
TargetSP target_sp(GetSP());
if (log)
@@ -622,72 +455,34 @@ SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error)
if (target_sp)
{
- Mutex::Locker api_locker (target_sp->GetAPIMutex());
-
- StateType state = eStateInvalid;
- process_sp = target_sp->GetProcessSP();
- if (process_sp)
+ ProcessAttachInfo &attach_info = sb_attach_info.ref();
+ if (attach_info.ProcessIDIsValid() && !attach_info.UserIDIsValid())
{
- state = process_sp->GetState();
-
- if (process_sp->IsAlive() && state != eStateConnected)
+ PlatformSP platform_sp = target_sp->GetPlatform();
+ // See if we can pre-verify if a process exists or not
+ if (platform_sp && platform_sp->IsConnected())
{
- if (state == eStateAttaching)
- error.SetErrorString ("process attach is in progress");
+ lldb::pid_t attach_pid = attach_info.GetProcessID();
+ ProcessInstanceInfo instance_info;
+ if (platform_sp->GetProcessInfo(attach_pid, instance_info))
+ {
+ attach_info.SetUserID(instance_info.GetEffectiveUserID());
+ }
else
- error.SetErrorString ("a process is already being debugged");
- if (log)
- log->Printf ("SBTarget(%p)::Attach (...) => error %s",
- static_cast<void*>(target_sp.get()),
- error.GetCString());
- return sb_process;
- }
- }
-
- if (state != eStateConnected)
- process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
-
- if (process_sp)
- {
- ProcessAttachInfo &attach_info = sb_attach_info.ref();
- if (attach_info.ProcessIDIsValid() && !attach_info.UserIDIsValid())
- {
- PlatformSP platform_sp = target_sp->GetPlatform();
- // See if we can pre-verify if a process exists or not
- if (platform_sp && platform_sp->IsConnected())
{
- lldb::pid_t attach_pid = attach_info.GetProcessID();
- ProcessInstanceInfo instance_info;
- if (platform_sp->GetProcessInfo(attach_pid, instance_info))
+ error.ref().SetErrorStringWithFormat("no process found with process ID %" PRIu64, attach_pid);
+ if (log)
{
- attach_info.SetUserID(instance_info.GetEffectiveUserID());
- }
- else
- {
- error.ref().SetErrorStringWithFormat("no process found with process ID %" PRIu64, attach_pid);
- if (log)
- {
- log->Printf ("SBTarget(%p)::Attach (...) => error %s",
- static_cast<void*>(target_sp.get()), error.GetCString());
- }
- return sb_process;
+ log->Printf ("SBTarget(%p)::Attach (...) => error %s",
+ static_cast<void*>(target_sp.get()), error.GetCString());
}
+ return sb_process;
}
}
- error.SetError (process_sp->Attach (attach_info));
- if (error.Success())
- {
- sb_process.SetSP (process_sp);
- // If we are doing synchronous mode, then wait for the
- // process to stop!
- if (target_sp->GetDebugger().GetAsyncExecution () == false)
- process_sp->WaitForProcessToStop (NULL);
- }
- }
- else
- {
- error.SetErrorString ("unable to create lldb_private::Process");
}
+ error.SetError(AttachToProcess(attach_info, *target_sp));
+ if (error.Success())
+ sb_process.SetSP(target_sp->GetProcessSP());
}
else
{
@@ -697,7 +492,7 @@ SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error)
if (log)
log->Printf ("SBTarget(%p)::Attach (...) => SBProcess(%p)",
static_cast<void*>(target_sp.get()),
- static_cast<void*>(process_sp.get()));
+ static_cast<void*>(sb_process.GetSP().get()));
return sb_process;
}
@@ -726,87 +521,37 @@ SBTarget::AttachToProcessWithID
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBProcess sb_process;
- ProcessSP process_sp;
TargetSP target_sp(GetSP());
if (log)
- log->Printf ("SBTarget(%p)::AttachToProcessWithID (listener, pid=%" PRId64 ", error)...",
- static_cast<void*>(target_sp.get()), pid);
+ log->Printf ("SBTarget(%p)::%s (listener, pid=%" PRId64 ", error)...",
+ static_cast<void*>(target_sp.get()),
+ __FUNCTION__,
+ pid);
if (target_sp)
{
- Mutex::Locker api_locker (target_sp->GetAPIMutex());
-
- StateType state = eStateInvalid;
- process_sp = target_sp->GetProcessSP();
- if (process_sp)
- {
- state = process_sp->GetState();
-
- if (process_sp->IsAlive() && state != eStateConnected)
- {
- if (state == eStateAttaching)
- error.SetErrorString ("process attach is in progress");
- else
- error.SetErrorString ("a process is already being debugged");
- return sb_process;
- }
- }
-
- if (state == eStateConnected)
- {
- // If we are already connected, then we have already specified the
- // listener, so if a valid listener is supplied, we need to error out
- // to let the client know.
- if (listener.IsValid())
- {
- error.SetErrorString ("process is connected and already has a listener, pass empty listener");
- return sb_process;
- }
- }
- else
- {
- if (listener.IsValid())
- process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL);
- else
- process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
- }
- if (process_sp)
- {
- sb_process.SetSP (process_sp);
+ ProcessAttachInfo attach_info;
+ attach_info.SetProcessID (pid);
+ if (listener.IsValid())
+ attach_info.SetListener(listener.GetSP());
- ProcessAttachInfo attach_info;
- attach_info.SetProcessID (pid);
+ ProcessInstanceInfo instance_info;
+ if (target_sp->GetPlatform ()->GetProcessInfo (pid, instance_info))
+ attach_info.SetUserID (instance_info.GetEffectiveUserID ());
- PlatformSP platform_sp = target_sp->GetPlatform();
- ProcessInstanceInfo instance_info;
- if (platform_sp->GetProcessInfo(pid, instance_info))
- {
- attach_info.SetUserID(instance_info.GetEffectiveUserID());
- }
- error.SetError (process_sp->Attach (attach_info));
- if (error.Success())
- {
- // If we are doing synchronous mode, then wait for the
- // process to stop!
- if (target_sp->GetDebugger().GetAsyncExecution () == false)
- process_sp->WaitForProcessToStop (NULL);
- }
- }
- else
- {
- error.SetErrorString ("unable to create lldb_private::Process");
- }
+ error.SetError (AttachToProcess (attach_info, *target_sp));
+ if (error.Success ())
+ sb_process.SetSP (target_sp->GetProcessSP ());
}
else
- {
error.SetErrorString ("SBTarget is invalid");
- }
if (log)
- log->Printf ("SBTarget(%p)::AttachToProcessWithID (...) => SBProcess(%p)",
- static_cast<void*>(target_sp.get()),
- static_cast<void*>(process_sp.get()));
+ log->Printf ("SBTarget(%p)::%s (...) => SBProcess(%p)",
+ static_cast<void*>(target_sp.get ()),
+ __FUNCTION__,
+ static_cast<void*>(sb_process.GetSP().get ()));
return sb_process;
}
@@ -822,82 +567,35 @@ SBTarget::AttachToProcessWithName
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBProcess sb_process;
- ProcessSP process_sp;
TargetSP target_sp(GetSP());
if (log)
- log->Printf ("SBTarget(%p)::AttachToProcessWithName (listener, name=%s, wait_for=%s, error)...",
- static_cast<void*>(target_sp.get()), name,
+ log->Printf ("SBTarget(%p)::%s (listener, name=%s, wait_for=%s, error)...",
+ static_cast<void*>(target_sp.get()),
+ __FUNCTION__,
+ name,
wait_for ? "true" : "false");
if (name && target_sp)
{
- Mutex::Locker api_locker (target_sp->GetAPIMutex());
-
- StateType state = eStateInvalid;
- process_sp = target_sp->GetProcessSP();
- if (process_sp)
- {
- state = process_sp->GetState();
-
- if (process_sp->IsAlive() && state != eStateConnected)
- {
- if (state == eStateAttaching)
- error.SetErrorString ("process attach is in progress");
- else
- error.SetErrorString ("a process is already being debugged");
- return sb_process;
- }
- }
-
- if (state == eStateConnected)
- {
- // If we are already connected, then we have already specified the
- // listener, so if a valid listener is supplied, we need to error out
- // to let the client know.
- if (listener.IsValid())
- {
- error.SetErrorString ("process is connected and already has a listener, pass empty listener");
- return sb_process;
- }
- }
- else
- {
- if (listener.IsValid())
- process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL);
- else
- process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
- }
+ ProcessAttachInfo attach_info;
+ attach_info.GetExecutableFile().SetFile(name, false);
+ attach_info.SetWaitForLaunch(wait_for);
+ if (listener.IsValid())
+ attach_info.SetListener(listener.GetSP());
- if (process_sp)
- {
- sb_process.SetSP (process_sp);
- ProcessAttachInfo attach_info;
- attach_info.GetExecutableFile().SetFile(name, false);
- attach_info.SetWaitForLaunch(wait_for);
- error.SetError (process_sp->Attach (attach_info));
- if (error.Success())
- {
- // If we are doing synchronous mode, then wait for the
- // process to stop!
- if (target_sp->GetDebugger().GetAsyncExecution () == false)
- process_sp->WaitForProcessToStop (NULL);
- }
- }
- else
- {
- error.SetErrorString ("unable to create lldb_private::Process");
- }
+ error.SetError (AttachToProcess (attach_info, *target_sp));
+ if (error.Success ())
+ sb_process.SetSP (target_sp->GetProcessSP ());
}
else
- {
error.SetErrorString ("SBTarget is invalid");
- }
if (log)
- log->Printf ("SBTarget(%p)::AttachToPorcessWithName (...) => SBProcess(%p)",
+ log->Printf ("SBTarget(%p)::%s (...) => SBProcess(%p)",
static_cast<void*>(target_sp.get()),
- static_cast<void*>(process_sp.get()));
+ __FUNCTION__,
+ static_cast<void*>(sb_process.GetSP().get()));
return sb_process;
}
@@ -1112,7 +810,8 @@ SBTarget::BreakpointCreateByLocation (const SBFileSpec &sb_file_spec,
const LazyBool skip_prologue = eLazyBoolCalculate;
const bool internal = false;
const bool hardware = false;
- *sb_bp = target_sp->CreateBreakpoint (NULL, *sb_file_spec, line, check_inlines, skip_prologue, internal, hardware);
+ const LazyBool move_to_nearest_code = eLazyBoolCalculate;
+ *sb_bp = target_sp->CreateBreakpoint (NULL, *sb_file_spec, line, check_inlines, skip_prologue, internal, hardware, move_to_nearest_code);
}
if (log)
@@ -1359,6 +1058,7 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
RegularExpression regexp(source_regex);
FileSpecList source_file_spec_list;
const bool hardware = false;
+ const LazyBool move_to_nearest_code = eLazyBoolCalculate;
source_file_spec_list.Append (source_file.ref());
if (module_name && module_name[0])
@@ -1366,11 +1066,11 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
FileSpecList module_spec_list;
module_spec_list.Append (FileSpec (module_name, false));
- *sb_bp = target_sp->CreateSourceRegexBreakpoint (&module_spec_list, &source_file_spec_list, regexp, false, hardware);
+ *sb_bp = target_sp->CreateSourceRegexBreakpoint (&module_spec_list, &source_file_spec_list, regexp, false, hardware, move_to_nearest_code);
}
else
{
- *sb_bp = target_sp->CreateSourceRegexBreakpoint (NULL, &source_file_spec_list, regexp, false, hardware);
+ *sb_bp = target_sp->CreateSourceRegexBreakpoint (NULL, &source_file_spec_list, regexp, false, hardware, move_to_nearest_code);
}
}
@@ -1387,9 +1087,9 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
}
lldb::SBBreakpoint
-SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
- const SBFileSpecList &module_list,
- const lldb::SBFileSpecList &source_file_list)
+SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
+ const SBFileSpecList &module_list,
+ const lldb::SBFileSpecList &source_file_list)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
@@ -1399,8 +1099,9 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
const bool hardware = false;
+ const LazyBool move_to_nearest_code = eLazyBoolCalculate;
RegularExpression regexp(source_regex);
- *sb_bp = target_sp->CreateSourceRegexBreakpoint (module_list.get(), source_file_list.get(), regexp, false, hardware);
+ *sb_bp = target_sp->CreateSourceRegexBreakpoint (module_list.get(), source_file_list.get(), regexp, false, hardware, move_to_nearest_code);
}
if (log)
@@ -2679,3 +2380,20 @@ SBTarget::GetStackRedZoneSize()
return 0;
}
+lldb::SBLaunchInfo
+SBTarget::GetLaunchInfo () const
+{
+ lldb::SBLaunchInfo launch_info(NULL);
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ launch_info.ref() = m_opaque_sp->GetProcessLaunchInfo();
+ return launch_info;
+}
+
+void
+SBTarget::SetLaunchInfo (const lldb::SBLaunchInfo &launch_info)
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ m_opaque_sp->SetProcessLaunchInfo(launch_info.ref());
+}
diff --git a/source/API/SBThread.cpp b/source/API/SBThread.cpp
index 9fe0d029496c..dfc7ce9629f3 100644
--- a/source/API/SBThread.cpp
+++ b/source/API/SBThread.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBThread.h"
#include "lldb/API/SBSymbolContext.h"
@@ -20,13 +18,15 @@
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StructuredData.h"
+#include "lldb/Core/ValueObject.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Queue.h"
-#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/UnixSignals.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlan.h"
@@ -114,13 +114,13 @@ SBThread::GetQueue () const
else
{
if (log)
- log->Printf ("SBThread(%p)::GetQueueKind() => error: process is running",
+ log->Printf ("SBThread(%p)::GetQueue() => error: process is running",
static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
if (log)
- log->Printf ("SBThread(%p)::GetQueueKind () => SBQueue(%p)",
+ log->Printf ("SBThread(%p)::GetQueue () => SBQueue(%p)",
static_cast<void*>(exe_ctx.GetThreadPtr()), static_cast<void*>(queue_sp.get()));
return sb_queue;
diff --git a/source/API/SBThreadPlan.cpp b/source/API/SBThreadPlan.cpp
index 02b1a8d893b6..2fcd72149409 100644
--- a/source/API/SBThreadPlan.cpp
+++ b/source/API/SBThreadPlan.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBThread.h"
#include "lldb/API/SBSymbolContext.h"
diff --git a/source/API/SBTypeCategory.cpp b/source/API/SBTypeCategory.cpp
index 66cf46236c65..ee9553ca6abd 100644
--- a/source/API/SBTypeCategory.cpp
+++ b/source/API/SBTypeCategory.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeCategory.h"
#include "lldb/API/SBTypeFilter.h"
diff --git a/source/API/SBTypeFilter.cpp b/source/API/SBTypeFilter.cpp
index 605e92de6991..8af3e1ff8641 100644
--- a/source/API/SBTypeFilter.cpp
+++ b/source/API/SBTypeFilter.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeFilter.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBTypeFormat.cpp b/source/API/SBTypeFormat.cpp
index d3ec9bc00bd0..9548fe904cdc 100644
--- a/source/API/SBTypeFormat.cpp
+++ b/source/API/SBTypeFormat.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeFormat.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBTypeNameSpecifier.cpp b/source/API/SBTypeNameSpecifier.cpp
index 3d03c6a0c539..c58747170b5a 100644
--- a/source/API/SBTypeNameSpecifier.cpp
+++ b/source/API/SBTypeNameSpecifier.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeNameSpecifier.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBTypeSummary.cpp b/source/API/SBTypeSummary.cpp
index 8a235bf50080..2c114545419c 100644
--- a/source/API/SBTypeSummary.cpp
+++ b/source/API/SBTypeSummary.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeSummary.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBTypeSynthetic.cpp b/source/API/SBTypeSynthetic.cpp
index 681ed6c032ab..6f9951dc5559 100644
--- a/source/API/SBTypeSynthetic.cpp
+++ b/source/API/SBTypeSynthetic.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBTypeSynthetic.h"
#include "lldb/API/SBStream.h"
diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp
index edecb93944ad..ef62c30e42cf 100644
--- a/source/API/SBValue.cpp
+++ b/source/API/SBValue.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/API/SBValue.h"
#include "lldb/API/SBDeclaration.h"
@@ -63,13 +61,19 @@ public:
lldb::DynamicValueType use_dynamic,
bool use_synthetic,
const char *name = NULL) :
- m_valobj_sp(in_valobj_sp),
+ m_valobj_sp(),
m_use_dynamic(use_dynamic),
m_use_synthetic(use_synthetic),
m_name (name)
{
- if (!m_name.IsEmpty() && m_valobj_sp)
- m_valobj_sp->SetName(m_name);
+ if (in_valobj_sp)
+ {
+ if ( (m_valobj_sp = in_valobj_sp->GetQualifiedRepresentationIfAvailable(lldb::eNoDynamicValues, false)) )
+ {
+ if (!m_name.IsEmpty())
+ m_valobj_sp->SetName(m_name);
+ }
+ }
}
ValueImpl (const ValueImpl& rhs) :
@@ -152,10 +156,20 @@ public:
return ValueObjectSP();
}
- if (value_sp->GetDynamicValue(m_use_dynamic))
- value_sp = value_sp->GetDynamicValue(m_use_dynamic);
- if (value_sp->GetSyntheticValue(m_use_synthetic))
- value_sp = value_sp->GetSyntheticValue(m_use_synthetic);
+ if (m_use_dynamic != eNoDynamicValues)
+ {
+ ValueObjectSP dynamic_sp = value_sp->GetDynamicValue(m_use_dynamic);
+ if (dynamic_sp)
+ value_sp = dynamic_sp;
+ }
+
+ if (m_use_synthetic)
+ {
+ ValueObjectSP synthetic_sp = value_sp->GetSyntheticValue(m_use_synthetic);
+ if (synthetic_sp)
+ value_sp = synthetic_sp;
+ }
+
if (!value_sp)
error.SetErrorString("invalid value object");
if (!m_name.IsEmpty())
@@ -969,14 +983,7 @@ SBValue::GetChildAtIndex (uint32_t idx, lldb::DynamicValueType use_dynamic, bool
child_sp = value_sp->GetChildAtIndex (idx, can_create);
if (can_create_synthetic && !child_sp)
{
- if (value_sp->IsPointerType())
- {
- child_sp = value_sp->GetSyntheticArrayMemberFromPointer(idx, can_create);
- }
- else if (value_sp->IsArrayType())
- {
- child_sp = value_sp->GetSyntheticArrayMemberFromArray(idx, can_create);
- }
+ child_sp = value_sp->GetSyntheticArrayMember(idx, can_create);
}
}
@@ -1244,6 +1251,22 @@ SBValue::MightHaveChildren ()
return has_children;
}
+bool
+SBValue::IsRuntimeSupportValue ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ bool is_support = false;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ is_support = value_sp->IsRuntimeSupportValue();
+
+ if (log)
+ log->Printf ("SBValue(%p)::IsRuntimeSupportValue() => %i",
+ static_cast<void*>(value_sp.get()), is_support);
+ return is_support;
+}
+
uint32_t
SBValue::GetNumChildren ()
{
diff --git a/source/API/SBVariablesOptions.cpp b/source/API/SBVariablesOptions.cpp
new file mode 100644
index 000000000000..7c453567c0ae
--- /dev/null
+++ b/source/API/SBVariablesOptions.cpp
@@ -0,0 +1,254 @@
+//===-- SBVariablesOptions.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lldb/API/SBVariablesOptions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class VariablesOptionsImpl
+{
+public:
+ VariablesOptionsImpl () :
+ m_include_arguments(false),
+ m_include_locals(false),
+ m_include_statics(false),
+ m_in_scope_only(false),
+ m_include_runtime_support_values(false),
+ m_use_dynamic(lldb::eNoDynamicValues)
+ {}
+
+ VariablesOptionsImpl (const VariablesOptionsImpl&) = default;
+
+ ~VariablesOptionsImpl () = default;
+
+ VariablesOptionsImpl&
+ operator = (const VariablesOptionsImpl&) = default;
+
+ bool
+ GetIncludeArguments () const
+ {
+ return m_include_arguments;
+ }
+
+ void
+ SetIncludeArguments (bool b)
+ {
+ m_include_arguments = b;
+ }
+
+ bool
+ GetIncludeLocals () const
+ {
+ return m_include_locals;
+ }
+
+ void
+ SetIncludeLocals (bool b)
+ {
+ m_include_locals = b;
+ }
+
+ bool
+ GetIncludeStatics () const
+ {
+ return m_include_statics;
+ }
+
+ void
+ SetIncludeStatics (bool b)
+ {
+ m_include_statics = b;
+ }
+
+ bool
+ GetInScopeOnly () const
+ {
+ return m_in_scope_only;
+ }
+
+ void
+ SetInScopeOnly (bool b)
+ {
+ m_in_scope_only = b;
+ }
+
+ bool
+ GetIncludeRuntimeSupportValues () const
+ {
+ return m_include_runtime_support_values;
+ }
+
+ void
+ SetIncludeRuntimeSupportValues (bool b)
+ {
+ m_include_runtime_support_values = b;
+ }
+
+ lldb::DynamicValueType
+ GetUseDynamic () const
+ {
+ return m_use_dynamic;
+ }
+
+ void
+ SetUseDynamic (lldb::DynamicValueType d)
+ {
+ m_use_dynamic = d;
+ }
+
+
+private:
+ bool m_include_arguments : 1;
+ bool m_include_locals : 1;
+ bool m_include_statics : 1;
+ bool m_in_scope_only : 1;
+ bool m_include_runtime_support_values : 1;
+ lldb::DynamicValueType m_use_dynamic;
+};
+
+SBVariablesOptions::SBVariablesOptions () :
+m_opaque_ap(new VariablesOptionsImpl())
+{
+}
+
+SBVariablesOptions::SBVariablesOptions (const SBVariablesOptions& options) :
+m_opaque_ap(new VariablesOptionsImpl(options.ref()))
+{
+}
+
+SBVariablesOptions&
+SBVariablesOptions::operator = (const SBVariablesOptions& options)
+{
+ m_opaque_ap.reset(new VariablesOptionsImpl(options.ref()));
+ return *this;
+}
+
+SBVariablesOptions::~SBVariablesOptions () = default;
+
+bool
+SBVariablesOptions::IsValid () const
+{
+ return m_opaque_ap.get() != nullptr;
+}
+
+bool
+SBVariablesOptions::GetIncludeArguments () const
+{
+ return m_opaque_ap->GetIncludeArguments();
+}
+
+void
+SBVariablesOptions::SetIncludeArguments (bool arguments)
+{
+ m_opaque_ap->SetIncludeArguments(arguments);
+}
+
+bool
+SBVariablesOptions::GetIncludeLocals () const
+{
+ return m_opaque_ap->GetIncludeLocals();
+}
+
+void
+SBVariablesOptions::SetIncludeLocals (bool locals)
+{
+ m_opaque_ap->SetIncludeLocals(locals);
+}
+
+bool
+SBVariablesOptions::GetIncludeStatics () const
+{
+ return m_opaque_ap->GetIncludeStatics();
+}
+
+void
+SBVariablesOptions::SetIncludeStatics (bool statics)
+{
+ m_opaque_ap->SetIncludeStatics(statics);
+}
+
+bool
+SBVariablesOptions::GetInScopeOnly () const
+{
+ return m_opaque_ap->GetInScopeOnly();
+}
+
+void
+SBVariablesOptions::SetInScopeOnly (bool in_scope_only)
+{
+ m_opaque_ap->SetInScopeOnly(in_scope_only);
+}
+
+bool
+SBVariablesOptions::GetIncludeRuntimeSupportValues () const
+{
+ return m_opaque_ap->GetIncludeRuntimeSupportValues();
+}
+
+void
+SBVariablesOptions::SetIncludeRuntimeSupportValues (bool runtime_support_values)
+{
+ m_opaque_ap->SetIncludeRuntimeSupportValues(runtime_support_values);
+}
+
+lldb::DynamicValueType
+SBVariablesOptions::GetUseDynamic () const
+{
+ return m_opaque_ap->GetUseDynamic();
+}
+
+void
+SBVariablesOptions::SetUseDynamic (lldb::DynamicValueType dynamic)
+{
+ m_opaque_ap->SetUseDynamic(dynamic);
+}
+
+VariablesOptionsImpl *
+SBVariablesOptions::operator->()
+{
+ return m_opaque_ap.operator->();
+}
+
+const VariablesOptionsImpl *
+SBVariablesOptions::operator->() const
+{
+ return m_opaque_ap.operator->();
+}
+
+VariablesOptionsImpl *
+SBVariablesOptions::get ()
+{
+ return m_opaque_ap.get();
+}
+
+VariablesOptionsImpl &
+SBVariablesOptions::ref()
+{
+ return *m_opaque_ap;
+}
+
+const VariablesOptionsImpl &
+SBVariablesOptions::ref() const
+{
+ return *m_opaque_ap;
+}
+
+SBVariablesOptions::SBVariablesOptions (VariablesOptionsImpl *lldb_object_ptr) :
+m_opaque_ap(std::move(lldb_object_ptr))
+{
+}
+
+void
+SBVariablesOptions::SetOptions (VariablesOptionsImpl *lldb_object_ptr)
+{
+ m_opaque_ap.reset(std::move(lldb_object_ptr));
+}
+
diff --git a/source/API/SystemInitializerFull.cpp b/source/API/SystemInitializerFull.cpp
new file mode 100644
index 000000000000..731d38a37bee
--- /dev/null
+++ b/source/API/SystemInitializerFull.cpp
@@ -0,0 +1,392 @@
+//===-- SystemInitializerFull.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SystemInitializerFull.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Initialization/SystemInitializerCommon.h"
+
+#include "Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h"
+#include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h"
+#include "Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h"
+#include "Plugins/ABI/SysV-arm/ABISysV_arm.h"
+#include "Plugins/ABI/SysV-arm64/ABISysV_arm64.h"
+#include "Plugins/ABI/SysV-i386/ABISysV_i386.h"
+#include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h"
+#include "Plugins/ABI/SysV-ppc/ABISysV_ppc.h"
+#include "Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h"
+#include "Plugins/ABI/SysV-mips/ABISysV_mips.h"
+#include "Plugins/ABI/SysV-mips64/ABISysV_mips64.h"
+#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h"
+#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
+#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
+#include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h"
+#include "Plugins/JITLoader/GDB/JITLoaderGDB.h"
+#include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h"
+#include "Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h"
+#include "Plugins/MemoryHistory/asan/MemoryHistoryASan.h"
+#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h"
+#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
+#include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
+#include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h"
+#include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h"
+#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
+
+#if defined(__APPLE__)
+#include "Plugins/Process/mach-core/ProcessMachCore.h"
+#include "Plugins/Process/MacOSX-Kernel/ProcessKDP.h"
+#include "Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h"
+#endif
+
+#if defined(__FreeBSD__)
+#include "Plugins/Process/FreeBSD/ProcessFreeBSD.h"
+#endif
+
+#if defined(_MSC_VER)
+#include "lldb/Host/windows/windows.h"
+#include "Plugins/Process/Windows/DynamicLoaderWindows.h"
+#include "Plugins/Process/Windows/ProcessWindows.h"
+#endif
+
+#if !defined(LLDB_DISABLE_PYTHON)
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+#endif
+
+#include "llvm/Support/TargetSelect.h"
+
+#include <string>
+
+using namespace lldb_private;
+
+#ifndef LLDB_DISABLE_PYTHON
+
+// Defined in the SWIG source file
+extern "C" void
+init_lldb(void);
+
+// these are the Pythonic implementations of the required callbacks
+// these are scripting-language specific, which is why they belong here
+// we still need to use function pointers to them instead of relying
+// on linkage-time resolution because the SWIG stuff and this file
+// get built at different times
+extern "C" bool
+LLDBSwigPythonBreakpointCallbackFunction (const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::StackFrameSP& sb_frame,
+ const lldb::BreakpointLocationSP& sb_bp_loc);
+
+extern "C" bool
+LLDBSwigPythonWatchpointCallbackFunction (const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::StackFrameSP& sb_frame,
+ const lldb::WatchpointSP& sb_wp);
+
+extern "C" bool
+LLDBSwigPythonCallTypeScript (const char *python_function_name,
+ void *session_dictionary,
+ const lldb::ValueObjectSP& valobj_sp,
+ void** pyfunct_wrapper,
+ const lldb::TypeSummaryOptionsSP& options_sp,
+ std::string& retval);
+
+extern "C" void*
+LLDBSwigPythonCreateSyntheticProvider (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ValueObjectSP& valobj_sp);
+
+extern "C" void*
+LLDBSwigPythonCreateCommandObject (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::DebuggerSP debugger_sp);
+
+extern "C" void*
+LLDBSwigPythonCreateScriptedThreadPlan (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ThreadPlanSP& thread_plan_sp);
+
+extern "C" bool
+LLDBSWIGPythonCallThreadPlan (void *implementor,
+ const char *method_name,
+ Event *event_sp,
+ bool &got_error);
+
+extern "C" size_t
+LLDBSwigPython_CalculateNumChildren (void *implementor);
+
+extern "C" void *
+LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx);
+
+extern "C" int
+LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name);
+
+extern "C" void *
+LLDBSWIGPython_CastPyObjectToSBValue (void* data);
+
+extern lldb::ValueObjectSP
+LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data);
+
+extern "C" bool
+LLDBSwigPython_UpdateSynthProviderInstance (void* implementor);
+
+extern "C" bool
+LLDBSwigPython_MightHaveChildrenSynthProviderInstance (void* implementor);
+
+extern "C" void *
+LLDBSwigPython_GetValueSynthProviderInstance (void* implementor);
+
+extern "C" bool
+LLDBSwigPythonCallCommand (const char *python_function_name,
+ const char *session_dictionary_name,
+ lldb::DebuggerSP& debugger,
+ const char* args,
+ lldb_private::CommandReturnObject &cmd_retobj,
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp);
+
+extern "C" bool
+LLDBSwigPythonCallCommandObject (void *implementor,
+ lldb::DebuggerSP& debugger,
+ const char* args,
+ lldb_private::CommandReturnObject& cmd_retobj,
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp);
+
+extern "C" bool
+LLDBSwigPythonCallModuleInit (const char *python_module_name,
+ const char *session_dictionary_name,
+ lldb::DebuggerSP& debugger);
+
+extern "C" void*
+LLDBSWIGPythonCreateOSPlugin (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ProcessSP& process_sp);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordProcess (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ProcessSP& process,
+ std::string& output);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordThread (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ThreadSP& thread,
+ std::string& output);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordTarget (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::TargetSP& target,
+ std::string& output);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordFrame (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::StackFrameSP& frame,
+ std::string& output);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordValue (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ValueObjectSP& value,
+ std::string& output);
+
+extern "C" void*
+LLDBSWIGPython_GetDynamicSetting (void* module,
+ const char* setting,
+ const lldb::TargetSP& target_sp);
+
+
+#endif
+
+SystemInitializerFull::SystemInitializerFull()
+{
+}
+
+SystemInitializerFull::~SystemInitializerFull()
+{
+}
+
+void
+SystemInitializerFull::Initialize()
+{
+ InitializeSWIG();
+
+ SystemInitializerCommon::Initialize();
+
+ // Initialize LLVM and Clang
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllDisassemblers();
+
+ ABIMacOSX_i386::Initialize();
+ ABIMacOSX_arm::Initialize();
+ ABIMacOSX_arm64::Initialize();
+ ABISysV_arm::Initialize();
+ ABISysV_arm64::Initialize();
+ ABISysV_i386::Initialize();
+ ABISysV_x86_64::Initialize();
+ ABISysV_ppc::Initialize();
+ ABISysV_ppc64::Initialize();
+ ABISysV_mips::Initialize();
+ ABISysV_mips64::Initialize();
+ DisassemblerLLVMC::Initialize();
+
+ JITLoaderGDB::Initialize();
+ ProcessElfCore::Initialize();
+ MemoryHistoryASan::Initialize();
+ AddressSanitizerRuntime::Initialize();
+
+ SymbolVendorELF::Initialize();
+ SymbolFileDWARF::Initialize();
+ SymbolFileSymtab::Initialize();
+ UnwindAssemblyInstEmulation::Initialize();
+ UnwindAssembly_x86::Initialize();
+ EmulateInstructionARM64::Initialize();
+ SymbolFileDWARFDebugMap::Initialize();
+ ItaniumABILanguageRuntime::Initialize();
+ AppleObjCRuntimeV2::Initialize();
+ AppleObjCRuntimeV1::Initialize();
+ SystemRuntimeMacOSX::Initialize();
+ RenderScriptRuntime::Initialize();
+
+#if defined(_MSC_VER)
+ DynamicLoaderWindows::Initialize();
+ ProcessWindows::Initialize();
+#endif
+#if defined(__FreeBSD__)
+ ProcessFreeBSD::Initialize();
+#endif
+#if defined(__APPLE__)
+ SymbolVendorMacOSX::Initialize();
+ ProcessKDP::Initialize();
+ ProcessMachCore::Initialize();
+#endif
+ //----------------------------------------------------------------------
+ // Platform agnostic plugins
+ //----------------------------------------------------------------------
+ platform_gdb_server::PlatformRemoteGDBServer::Initialize();
+
+ process_gdb_remote::ProcessGDBRemote::Initialize();
+ DynamicLoaderStatic::Initialize();
+
+ // Scan for any system or user LLDB plug-ins
+ PluginManager::Initialize();
+
+ // The process settings need to know about installed plug-ins, so the Settings must be initialized
+ // AFTER PluginManager::Initialize is called.
+
+ Debugger::SettingsInitialize();
+}
+
+void SystemInitializerFull::InitializeSWIG()
+{
+#if !defined(LLDB_DISABLE_PYTHON)
+ ScriptInterpreterPython::InitializeInterpreter(
+ init_lldb,
+ LLDBSwigPythonBreakpointCallbackFunction,
+ LLDBSwigPythonWatchpointCallbackFunction,
+ LLDBSwigPythonCallTypeScript,
+ LLDBSwigPythonCreateSyntheticProvider,
+ LLDBSwigPythonCreateCommandObject,
+ LLDBSwigPython_CalculateNumChildren,
+ LLDBSwigPython_GetChildAtIndex,
+ LLDBSwigPython_GetIndexOfChildWithName,
+ LLDBSWIGPython_CastPyObjectToSBValue,
+ LLDBSWIGPython_GetValueObjectSPFromSBValue,
+ LLDBSwigPython_UpdateSynthProviderInstance,
+ LLDBSwigPython_MightHaveChildrenSynthProviderInstance,
+ LLDBSwigPython_GetValueSynthProviderInstance,
+ LLDBSwigPythonCallCommand,
+ LLDBSwigPythonCallCommandObject,
+ LLDBSwigPythonCallModuleInit,
+ LLDBSWIGPythonCreateOSPlugin,
+ LLDBSWIGPythonRunScriptKeywordProcess,
+ LLDBSWIGPythonRunScriptKeywordThread,
+ LLDBSWIGPythonRunScriptKeywordTarget,
+ LLDBSWIGPythonRunScriptKeywordFrame,
+ LLDBSWIGPythonRunScriptKeywordValue,
+ LLDBSWIGPython_GetDynamicSetting,
+ LLDBSwigPythonCreateScriptedThreadPlan,
+ LLDBSWIGPythonCallThreadPlan);
+#endif
+}
+
+void
+SystemInitializerFull::Terminate()
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ Debugger::SettingsTerminate();
+
+ // Terminate and unload and loaded system or user LLDB plug-ins
+ PluginManager::Terminate();
+ ABIMacOSX_i386::Terminate();
+ ABIMacOSX_arm::Terminate();
+ ABIMacOSX_arm64::Terminate();
+ ABISysV_arm::Terminate();
+ ABISysV_arm64::Terminate();
+ ABISysV_i386::Terminate();
+ ABISysV_x86_64::Terminate();
+ ABISysV_ppc::Terminate();
+ ABISysV_ppc64::Terminate();
+ ABISysV_mips::Terminate();
+ ABISysV_mips64::Terminate();
+ DisassemblerLLVMC::Terminate();
+
+ JITLoaderGDB::Terminate();
+ ProcessElfCore::Terminate();
+ MemoryHistoryASan::Terminate();
+ AddressSanitizerRuntime::Terminate();
+ SymbolVendorELF::Terminate();
+ SymbolFileDWARF::Terminate();
+ SymbolFileSymtab::Terminate();
+ UnwindAssembly_x86::Terminate();
+ UnwindAssemblyInstEmulation::Terminate();
+ EmulateInstructionARM64::Terminate();
+ SymbolFileDWARFDebugMap::Terminate();
+ ItaniumABILanguageRuntime::Terminate();
+ AppleObjCRuntimeV2::Terminate();
+ AppleObjCRuntimeV1::Terminate();
+ SystemRuntimeMacOSX::Terminate();
+ RenderScriptRuntime::Terminate();
+
+#if defined(__APPLE__)
+ ProcessMachCore::Terminate();
+ ProcessKDP::Terminate();
+ SymbolVendorMacOSX::Terminate();
+#endif
+#if defined(_MSC_VER)
+ DynamicLoaderWindows::Terminate();
+#endif
+
+#if defined(__FreeBSD__)
+ ProcessFreeBSD::Terminate();
+#endif
+ Debugger::SettingsTerminate();
+
+ platform_gdb_server::PlatformRemoteGDBServer::Terminate();
+ process_gdb_remote::ProcessGDBRemote::Terminate();
+ DynamicLoaderStatic::Terminate();
+
+ // Now shutdown the common parts, in reverse order.
+ SystemInitializerCommon::Terminate();
+}
+
+void SystemInitializerFull::TerminateSWIG()
+{
+
+}
diff --git a/source/Breakpoint/Breakpoint.cpp b/source/Breakpoint/Breakpoint.cpp
index beb0f6bc5a6e..23d484f0f68a 100644
--- a/source/Breakpoint/Breakpoint.cpp
+++ b/source/Breakpoint/Breakpoint.cpp
@@ -31,7 +31,6 @@
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
-#include "lldb/lldb-private-log.h"
#include "llvm/Support/Casting.h"
using namespace lldb;
@@ -877,25 +876,18 @@ Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_l
{
s->Printf ("no locations (pending).");
}
- else if (num_locations == 1)
+ else if (num_locations == 1 && show_locations == false)
{
- // If there is one location only, we'll just print that location information. But don't do this if
- // show locations is true, then that will be handled below.
- if (show_locations == false)
- {
- GetLocationAtIndex(0)->GetDescription(s, level);
- }
- else
- {
- s->Printf ("%zd locations.", num_locations);
- }
+ // There is only one location, so we'll just print that location information.
+ GetLocationAtIndex(0)->GetDescription(s, level);
}
else
{
- s->Printf ("%zd locations.", num_locations);
+ s->Printf ("%" PRIu64 " locations.", static_cast<uint64_t>(num_locations));
}
s->EOL();
break;
+
case lldb::eDescriptionLevelVerbose:
// Verbose mode does a debug dump of the breakpoint
Dump (s);
@@ -957,6 +949,34 @@ Breakpoint::GetFilterDescription (Stream *s)
m_filter_sp->GetDescription (s);
}
+bool
+Breakpoint::EvaluatePrecondition (StoppointCallbackContext &context)
+{
+ if (!m_precondition_sp)
+ return true;
+
+ return m_precondition_sp->EvaluatePrecondition(context);
+}
+
+bool
+Breakpoint::BreakpointPrecondition::EvaluatePrecondition(StoppointCallbackContext &context)
+{
+ return true;
+}
+
+void
+Breakpoint::BreakpointPrecondition::DescribePrecondition(Stream &stream, lldb::DescriptionLevel level)
+{
+}
+
+Error
+Breakpoint::BreakpointPrecondition::ConfigurePrecondition(Args &options)
+{
+ Error error;
+ error.SetErrorString("Base breakpoint precondition has no options.");
+ return error;
+}
+
void
Breakpoint::SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind)
{
diff --git a/source/Breakpoint/BreakpointLocation.cpp b/source/Breakpoint/BreakpointLocation.cpp
index 85233c9374cb..ef9144778df0 100644
--- a/source/Breakpoint/BreakpointLocation.cpp
+++ b/source/Breakpoint/BreakpointLocation.cpp
@@ -7,15 +7,12 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
// C Includes
// C++ Includes
#include <string>
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/BreakpointID.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
@@ -23,6 +20,8 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Expression/ClangUserExpression.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/Target.h"
@@ -535,6 +534,7 @@ bool
BreakpointLocation::SetBreakpointSite (BreakpointSiteSP& bp_site_sp)
{
m_bp_site_sp = bp_site_sp;
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeLocationsResolved);
return true;
}
@@ -590,7 +590,7 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
s->PutCString ("re-exported target = ");
else
s->PutCString("where = ");
- sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false, true);
+ sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false, true, true);
}
else
{
diff --git a/source/Breakpoint/BreakpointLocationCollection.cpp b/source/Breakpoint/BreakpointLocationCollection.cpp
index 5756ccedfaa4..5b6e746f911d 100644
--- a/source/Breakpoint/BreakpointLocationCollection.cpp
+++ b/source/Breakpoint/BreakpointLocationCollection.cpp
@@ -138,11 +138,17 @@ bool
BreakpointLocationCollection::ShouldStop (StoppointCallbackContext *context)
{
bool shouldStop = false;
- const size_t count = GetSize();
- for (size_t i = 0; i < count; i++)
+ size_t i = 0;
+ size_t prev_size = GetSize();
+ while (i < prev_size)
{
+ // ShouldStop can remove the breakpoint from the list
if (GetByIndex(i)->ShouldStop(context))
shouldStop = true;
+
+ if (prev_size == GetSize())
+ i++;
+ prev_size = GetSize();
}
return shouldStop;
}
diff --git a/source/Breakpoint/BreakpointResolver.cpp b/source/Breakpoint/BreakpointResolver.cpp
index 33b0ff40e35f..f02eadf86a7c 100644
--- a/source/Breakpoint/BreakpointResolver.cpp
+++ b/source/Breakpoint/BreakpointResolver.cpp
@@ -25,7 +25,6 @@
#include "lldb/Target/Target.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb_private;
using namespace lldb;
diff --git a/source/Breakpoint/BreakpointResolverAddress.cpp b/source/Breakpoint/BreakpointResolverAddress.cpp
index d6647130c54c..193bc413af05 100644
--- a/source/Breakpoint/BreakpointResolverAddress.cpp
+++ b/source/Breakpoint/BreakpointResolverAddress.cpp
@@ -13,11 +13,11 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
using namespace lldb;
diff --git a/source/Breakpoint/BreakpointResolverFileLine.cpp b/source/Breakpoint/BreakpointResolverFileLine.cpp
index 950054c3d720..408998ec83ab 100644
--- a/source/Breakpoint/BreakpointResolverFileLine.cpp
+++ b/source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -19,7 +19,6 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
@@ -33,13 +32,15 @@ BreakpointResolverFileLine::BreakpointResolverFileLine
const FileSpec &file_spec,
uint32_t line_no,
bool check_inlines,
- bool skip_prologue
+ bool skip_prologue,
+ bool exact_match
) :
BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver),
m_file_spec (file_spec),
m_line_number (line_no),
m_inlines (check_inlines),
- m_skip_prologue(skip_prologue)
+ m_skip_prologue(skip_prologue),
+ m_exact_match(exact_match)
{
}
@@ -79,7 +80,7 @@ BreakpointResolverFileLine::SearchCallback
if (cu_sp)
{
if (filter.CompUnitPasses(*cu_sp))
- cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list);
+ cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, m_exact_match, eSymbolContextEverything, sc_list);
}
}
StreamString s;
@@ -101,7 +102,7 @@ BreakpointResolverFileLine::GetDepth()
void
BreakpointResolverFileLine::GetDescription (Stream *s)
{
- s->Printf ("file = '%s', line = %u", m_file_spec.GetPath().c_str(), m_line_number);
+ s->Printf ("file = '%s', line = %u, exact_match = %d", m_file_spec.GetPath().c_str(), m_line_number, m_exact_match);
}
void
@@ -117,7 +118,8 @@ BreakpointResolverFileLine::CopyForBreakpoint (Breakpoint &breakpoint)
m_file_spec,
m_line_number,
m_inlines,
- m_skip_prologue));
+ m_skip_prologue,
+ m_exact_match));
return ret_sp;
}
diff --git a/source/Breakpoint/BreakpointResolverFileRegex.cpp b/source/Breakpoint/BreakpointResolverFileRegex.cpp
index c71d9bf5ba8c..e7bce0524c57 100644
--- a/source/Breakpoint/BreakpointResolverFileRegex.cpp
+++ b/source/Breakpoint/BreakpointResolverFileRegex.cpp
@@ -19,7 +19,6 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/Target.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
@@ -30,10 +29,12 @@ using namespace lldb_private;
BreakpointResolverFileRegex::BreakpointResolverFileRegex
(
Breakpoint *bkpt,
- RegularExpression &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;
-}