aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/API/SBAddress.cpp42
-rw-r--r--source/API/SBBreakpoint.cpp78
-rw-r--r--source/API/SBCommandInterpreter.cpp192
-rw-r--r--source/API/SBCommunication.cpp4
-rw-r--r--source/API/SBCompileUnit.cpp8
-rw-r--r--source/API/SBDebugger.cpp71
-rw-r--r--source/API/SBEvent.cpp6
-rw-r--r--source/API/SBExecutionContext.cpp129
-rw-r--r--source/API/SBFunction.cpp10
-rw-r--r--source/API/SBHostOS.cpp36
-rw-r--r--source/API/SBInstruction.cpp17
-rw-r--r--source/API/SBInstructionList.cpp16
-rw-r--r--source/API/SBListener.cpp6
-rw-r--r--source/API/SBPlatform.cpp3
-rw-r--r--source/API/SBProcess.cpp44
-rw-r--r--source/API/SBSection.cpp8
-rw-r--r--source/API/SBTarget.cpp306
-rw-r--r--source/API/SBThread.cpp105
-rw-r--r--source/API/SBThreadCollection.cpp97
-rw-r--r--source/API/SBThreadPlan.cpp285
-rw-r--r--source/API/SBType.cpp173
-rw-r--r--source/API/SBTypeSummary.cpp97
-rw-r--r--source/API/SBValue.cpp123
-rw-r--r--source/API/SBValueList.cpp24
-rw-r--r--source/Breakpoint/Breakpoint.cpp398
-rw-r--r--source/Breakpoint/BreakpointID.cpp17
-rw-r--r--source/Breakpoint/BreakpointIDList.cpp44
-rw-r--r--source/Breakpoint/BreakpointLocation.cpp23
-rw-r--r--source/Breakpoint/BreakpointLocationCollection.cpp1
-rw-r--r--source/Breakpoint/BreakpointLocationList.cpp27
-rw-r--r--source/Breakpoint/BreakpointOptions.cpp3
-rw-r--r--source/Breakpoint/BreakpointResolverAddress.cpp8
-rw-r--r--source/Breakpoint/BreakpointResolverFileLine.cpp11
-rw-r--r--source/Breakpoint/BreakpointResolverFileRegex.cpp7
-rw-r--r--source/Breakpoint/BreakpointResolverName.cpp18
-rw-r--r--source/Breakpoint/BreakpointSite.cpp9
-rw-r--r--source/Commands/CommandCompletions.cpp6
-rw-r--r--source/Commands/CommandObjectBreakpoint.cpp588
-rw-r--r--source/Commands/CommandObjectBreakpoint.h14
-rw-r--r--source/Commands/CommandObjectBreakpointCommand.cpp112
-rw-r--r--source/Commands/CommandObjectCommands.cpp238
-rw-r--r--source/Commands/CommandObjectExpression.cpp6
-rw-r--r--source/Commands/CommandObjectMemory.cpp113
-rw-r--r--source/Commands/CommandObjectPlatform.cpp5
-rw-r--r--source/Commands/CommandObjectProcess.cpp27
-rw-r--r--source/Commands/CommandObjectSource.cpp12
-rw-r--r--source/Commands/CommandObjectSyntax.cpp6
-rw-r--r--source/Commands/CommandObjectTarget.cpp120
-rw-r--r--source/Commands/CommandObjectThread.cpp666
-rw-r--r--source/Commands/CommandObjectType.cpp125
-rw-r--r--source/Commands/CommandObjectWatchpointCommand.cpp15
-rw-r--r--source/Core/Address.cpp13
-rw-r--r--source/Core/AddressRange.cpp2
-rw-r--r--source/Core/AddressResolverFileLine.cpp2
-rw-r--r--source/Core/ArchSpec.cpp141
-rw-r--r--source/Core/Communication.cpp25
-rw-r--r--source/Core/Connection.cpp16
-rw-r--r--source/Core/ConnectionSharedMemory.cpp2
-rw-r--r--source/Core/ConstString.cpp25
-rw-r--r--source/Core/DataExtractor.cpp52
-rw-r--r--source/Core/Debugger.cpp509
-rw-r--r--source/Core/Disassembler.cpp55
-rw-r--r--source/Core/FastDemangle.cpp1496
-rw-r--r--source/Core/FileSpecList.cpp4
-rw-r--r--source/Core/IOHandler.cpp236
-rw-r--r--source/Core/Log.cpp8
-rw-r--r--source/Core/Mangled.cpp61
-rw-r--r--source/Core/Module.cpp37
-rw-r--r--source/Core/ModuleList.cpp20
-rw-r--r--source/Core/PluginManager.cpp223
-rw-r--r--source/Core/RegularExpression.cpp20
-rw-r--r--source/Core/SearchFilter.cpp92
-rw-r--r--source/Core/Section.cpp14
-rw-r--r--source/Core/StreamString.cpp16
-rw-r--r--source/Core/ValueObject.cpp520
-rw-r--r--source/Core/ValueObjectCast.cpp2
-rw-r--r--source/Core/ValueObjectChild.cpp2
-rw-r--r--source/Core/ValueObjectConstResult.cpp18
-rw-r--r--source/Core/ValueObjectConstResultImpl.cpp56
-rw-r--r--source/Core/ValueObjectDynamicValue.cpp13
-rw-r--r--source/Core/ValueObjectMemory.cpp2
-rw-r--r--source/Core/ValueObjectSyntheticFilter.cpp60
-rw-r--r--source/Core/ValueObjectVariable.cpp43
-rw-r--r--source/DataFormatters/CF.cpp8
-rw-r--r--source/DataFormatters/CXXFormatterFunctions.cpp580
-rw-r--r--source/DataFormatters/Cocoa.cpp28
-rw-r--r--source/DataFormatters/DataVisualization.cpp24
-rw-r--r--source/DataFormatters/FormatCache.cpp76
-rw-r--r--source/DataFormatters/FormatManager.cpp205
-rw-r--r--source/DataFormatters/LibCxx.cpp113
-rw-r--r--source/DataFormatters/LibCxxInitializerList.cpp145
-rw-r--r--source/DataFormatters/LibCxxList.cpp61
-rw-r--r--source/DataFormatters/LibCxxMap.cpp215
-rw-r--r--source/DataFormatters/LibCxxUnorderedMap.cpp35
-rw-r--r--source/DataFormatters/LibCxxVector.cpp157
-rw-r--r--source/DataFormatters/LibStdcpp.cpp2
-rw-r--r--source/DataFormatters/NSArray.cpp17
-rw-r--r--source/DataFormatters/NSDictionary.cpp197
-rw-r--r--source/DataFormatters/NSIndexPath.cpp309
-rw-r--r--source/DataFormatters/NSSet.cpp178
-rw-r--r--source/DataFormatters/StringPrinter.cpp650
-rw-r--r--source/DataFormatters/TypeCategory.cpp97
-rw-r--r--source/DataFormatters/TypeCategoryMap.cpp68
-rw-r--r--source/DataFormatters/TypeFormat.cpp12
-rw-r--r--source/DataFormatters/TypeSummary.cpp56
-rw-r--r--source/DataFormatters/TypeSynthetic.cpp138
-rw-r--r--source/DataFormatters/TypeValidator.cpp75
-rw-r--r--source/DataFormatters/ValueObjectPrinter.cpp108
-rw-r--r--source/Expression/ClangASTSource.cpp239
-rw-r--r--source/Expression/ClangExpressionDeclMap.cpp51
-rw-r--r--source/Expression/ClangExpressionParser.cpp83
-rw-r--r--source/Expression/ClangExpressionVariable.cpp11
-rw-r--r--source/Expression/ClangFunction.cpp22
-rw-r--r--source/Expression/ClangModulesDeclVendor.cpp372
-rw-r--r--source/Expression/ClangUserExpression.cpp25
-rw-r--r--source/Expression/DWARFExpression.cpp7
-rw-r--r--source/Expression/IRExecutionUnit.cpp128
-rw-r--r--source/Expression/IRForTarget.cpp54
-rw-r--r--source/Host/common/Editline.cpp1735
-rw-r--r--source/Host/common/File.cpp2
-rw-r--r--source/Host/common/FileSpec.cpp189
-rw-r--r--source/Host/common/Host.cpp471
-rw-r--r--source/Host/common/HostInfoBase.cpp36
-rw-r--r--source/Host/common/HostNativeThreadBase.cpp82
-rw-r--r--source/Host/common/HostProcess.cpp65
-rw-r--r--source/Host/common/HostThread.cpp78
-rw-r--r--source/Host/common/MonitoringProcessLauncher.cpp102
-rw-r--r--source/Host/common/NativeProcessProtocol.cpp23
-rw-r--r--source/Host/common/NativeProcessProtocol.h23
-rw-r--r--source/Host/common/NativeThreadProtocol.h2
-rw-r--r--source/Host/common/Pipe.cpp171
-rw-r--r--source/Host/common/PipeBase.cpp27
-rw-r--r--source/Host/common/Socket.cpp78
-rw-r--r--source/Host/common/SocketAddress.cpp10
-rw-r--r--source/Host/common/SoftwareBreakpoint.cpp19
-rw-r--r--source/Host/common/ThisThread.cpp52
-rw-r--r--source/Host/common/ThreadLauncher.cpp74
-rw-r--r--source/Host/freebsd/Host.cpp114
-rw-r--r--source/Host/freebsd/HostInfoFreeBSD.cpp6
-rw-r--r--source/Host/freebsd/HostThreadFreeBSD.cpp77
-rw-r--r--source/Host/freebsd/ThisThread.cpp30
-rw-r--r--source/Host/posix/ConnectionFileDescriptorPosix.cpp (renamed from source/Core/ConnectionFileDescriptor.cpp)478
-rw-r--r--source/Host/posix/HostInfoPosix.cpp14
-rw-r--r--source/Host/posix/HostProcessPosix.cpp47
-rw-r--r--source/Host/posix/HostThreadPosix.cpp74
-rw-r--r--source/Host/posix/PipePosix.cpp378
-rw-r--r--source/Host/posix/ProcessLauncherPosix.cpp33
-rw-r--r--source/Interpreter/Args.cpp33
-rw-r--r--source/Interpreter/CommandInterpreter.cpp337
-rw-r--r--source/Interpreter/CommandObject.cpp53
-rw-r--r--source/Interpreter/CommandObjectRegexCommand.cpp6
-rw-r--r--source/Interpreter/OptionGroupPlatform.cpp2
-rw-r--r--source/Interpreter/OptionGroupValueObjectDisplay.cpp13
-rw-r--r--source/Interpreter/OptionValue.cpp39
-rw-r--r--source/Interpreter/OptionValueArch.cpp4
-rw-r--r--source/Interpreter/OptionValueArray.cpp2
-rw-r--r--source/Interpreter/OptionValueBoolean.cpp2
-rw-r--r--source/Interpreter/OptionValueChar.cpp80
-rw-r--r--source/Interpreter/OptionValueDictionary.cpp6
-rw-r--r--source/Interpreter/OptionValueEnumeration.cpp2
-rw-r--r--source/Interpreter/OptionValueFileSpec.cpp2
-rw-r--r--source/Interpreter/OptionValueFileSpecLIst.cpp8
-rw-r--r--source/Interpreter/OptionValueFormat.cpp2
-rw-r--r--source/Interpreter/OptionValuePathMappings.cpp8
-rw-r--r--source/Interpreter/OptionValueProperties.cpp10
-rw-r--r--source/Interpreter/OptionValueRegex.cpp2
-rw-r--r--source/Interpreter/OptionValueSInt64.cpp2
-rw-r--r--source/Interpreter/OptionValueString.cpp37
-rw-r--r--source/Interpreter/OptionValueUInt64.cpp2
-rw-r--r--source/Interpreter/OptionValueUUID.cpp4
-rw-r--r--source/Interpreter/Property.cpp15
-rw-r--r--source/Interpreter/ScriptInterpreter.cpp12
-rw-r--r--source/Interpreter/ScriptInterpreterPython.cpp221
-rw-r--r--source/Interpreter/embedded_interpreter.py2
-rw-r--r--source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp30
-rw-r--r--source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h14
-rw-r--r--source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp34
-rw-r--r--source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h16
-rw-r--r--source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h14
-rw-r--r--source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h14
-rw-r--r--source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp1120
-rw-r--r--source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h143
-rw-r--r--source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp1124
-rw-r--r--source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h143
-rw-r--r--source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp14
-rw-r--r--source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h14
-rw-r--r--source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp37
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp28
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp189
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h4
-rw-r--r--source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp2
-rw-r--r--source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp314
-rw-r--r--source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h86
-rw-r--r--source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp30
-rw-r--r--source/Plugins/JITLoader/GDB/JITLoaderGDB.h4
-rw-r--r--source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp183
-rw-r--r--source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h62
-rw-r--r--source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp2
-rw-r--r--source/Plugins/ObjectFile/ELF/ELFHeader.cpp9
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp135
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.h3
-rw-r--r--source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp77
-rw-r--r--source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h6
-rw-r--r--source/Plugins/Platform/POSIX/PlatformPOSIX.cpp130
-rw-r--r--source/Plugins/Platform/POSIX/PlatformPOSIX.h56
-rw-r--r--source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp26
-rw-r--r--source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h7
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp3
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.cpp66
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.h7
-rw-r--r--source/Plugins/Process/POSIX/POSIXThread.cpp45
-rw-r--r--source/Plugins/Process/POSIX/POSIXThread.h2
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIX.cpp39
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIX.h59
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp4
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp4
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp321
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h95
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp9
-rw-r--r--source/Plugins/Process/Utility/ARMDefines.h34
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.cpp12
-rw-r--r--source/Plugins/Process/Utility/HistoryThread.cpp2
-rw-r--r--source/Plugins/Process/Utility/HistoryThread.h12
-rw-r--r--source/Plugins/Process/Utility/HistoryUnwind.cpp2
-rw-r--r--source/Plugins/Process/Utility/HistoryUnwind.h3
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.cpp24
-rw-r--r--source/Plugins/Process/Utility/InstructionUtils.h2
-rw-r--r--source/Plugins/Process/Utility/LinuxSignals.cpp2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp230
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h66
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.cpp703
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.h26
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp3
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp273
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h173
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp578
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h277
-rw-r--r--source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp2
-rw-r--r--source/Plugins/Process/Utility/RegisterContext_powerpc.h163
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_arm64.h4
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_i386.h18
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_powerpc.h144
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_x86_64.h34
-rw-r--r--source/Plugins/Process/Utility/StopInfoMachException.cpp8
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.cpp46
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.h3
-rw-r--r--source/Plugins/Process/Utility/lldb-x86-register-enums.h461
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.cpp25
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.h24
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp2
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp109
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h62
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp2
-rw-r--r--source/Plugins/Process/elf-core/ThreadElfCore.cpp20
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp118
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h4
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp61
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp236
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h19
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp134
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.h97
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp16
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp29
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h15
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h3
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp24
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp91
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp20
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h1
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp2
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp153
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFFormValue.h23
-rw-r--r--source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h6
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp280
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h5
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp3
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp473
-rw-r--r--source/Symbol/ClangASTContext.cpp67
-rw-r--r--source/Symbol/ClangASTImporter.cpp2
-rw-r--r--source/Symbol/ClangASTType.cpp225
-rw-r--r--source/Symbol/ClangExternalASTSourceCommon.cpp38
-rw-r--r--source/Symbol/CompactUnwindInfo.cpp1215
-rw-r--r--source/Symbol/CompileUnit.cpp7
-rw-r--r--source/Symbol/DWARFCallFrameInfo.cpp41
-rw-r--r--source/Symbol/Declaration.cpp2
-rw-r--r--source/Symbol/FuncUnwinders.cpp379
-rw-r--r--source/Symbol/LineTable.cpp1
-rw-r--r--source/Symbol/ObjectFile.cpp6
-rw-r--r--source/Symbol/Symbol.cpp2
-rw-r--r--source/Symbol/SymbolContext.cpp12
-rw-r--r--source/Symbol/Type.cpp112
-rw-r--r--source/Symbol/UnwindPlan.cpp77
-rw-r--r--source/Symbol/UnwindTable.cpp16
-rw-r--r--source/Symbol/Variable.cpp4
-rw-r--r--source/Target/CPPLanguageRuntime.cpp78
-rw-r--r--source/Target/FileAction.cpp32
-rw-r--r--source/Target/InstrumentationRuntime.cpp48
-rw-r--r--source/Target/InstrumentationRuntimeStopInfo.cpp36
-rw-r--r--source/Target/LanguageRuntime.cpp56
-rw-r--r--source/Target/Memory.cpp19
-rw-r--r--source/Target/MemoryHistory.cpp30
-rw-r--r--source/Target/ObjCLanguageRuntime.cpp8
-rw-r--r--source/Target/Platform.cpp281
-rw-r--r--source/Target/Process.cpp518
-rw-r--r--source/Target/ProcessLaunchInfo.cpp180
-rw-r--r--source/Target/StackFrame.cpp55
-rw-r--r--source/Target/StackFrameList.cpp15
-rw-r--r--source/Target/StopInfo.cpp24
-rw-r--r--source/Target/Target.cpp218
-rw-r--r--source/Target/TargetList.cpp134
-rw-r--r--source/Target/Thread.cpp259
-rw-r--r--source/Target/ThreadCollection.cpp62
-rw-r--r--source/Target/ThreadList.cpp23
-rw-r--r--source/Target/ThreadPlanPython.cpp192
-rw-r--r--source/Target/ThreadPlanStepInRange.cpp30
-rw-r--r--source/Target/ThreadPlanStepInstruction.cpp29
-rw-r--r--source/Target/ThreadPlanStepOut.cpp51
-rw-r--r--source/Target/ThreadPlanStepOverBreakpoint.cpp35
-rw-r--r--source/Target/ThreadPlanStepOverRange.cpp26
-rw-r--r--source/Target/ThreadPlanStepRange.cpp8
-rw-r--r--source/Target/ThreadPlanStepThrough.cpp5
-rw-r--r--source/Target/ThreadPlanTracer.cpp6
-rw-r--r--source/Utility/PseudoTerminal.cpp6
-rw-r--r--source/Utility/RegisterNumber.cpp157
-rw-r--r--source/Utility/StringExtractor.cpp105
-rw-r--r--source/Utility/StringExtractor.h7
-rw-r--r--source/Utility/StringExtractorGDBRemote.cpp13
-rw-r--r--source/Utility/StringLexer.cpp78
-rw-r--r--source/Utility/UriParser.cpp58
-rw-r--r--source/Utility/UriParser.h31
-rw-r--r--source/lldb-log.cpp3
-rw-r--r--source/lldb.cpp39
332 files changed, 25749 insertions, 7724 deletions
diff --git a/source/API/SBAddress.cpp b/source/API/SBAddress.cpp
index 6aec0722169f..d6e32b60059b 100644
--- a/source/API/SBAddress.cpp
+++ b/source/API/SBAddress.cpp
@@ -23,19 +23,19 @@ using namespace lldb_private;
SBAddress::SBAddress () :
- m_opaque_ap ()
+ m_opaque_ap (new Address())
{
}
SBAddress::SBAddress (const Address *lldb_object_ptr) :
- m_opaque_ap ()
+ m_opaque_ap (new Address())
{
if (lldb_object_ptr)
ref() = *lldb_object_ptr;
}
SBAddress::SBAddress (const SBAddress &rhs) :
- m_opaque_ap ()
+ m_opaque_ap (new Address())
{
if (rhs.IsValid())
ref() = rhs.ref();
@@ -49,7 +49,7 @@ SBAddress::SBAddress (lldb::SBSection section, lldb::addr_t offset) :
// Create an address by resolving a load address using the supplied target
SBAddress::SBAddress (lldb::addr_t load_addr, lldb::SBTarget &target) :
- m_opaque_ap()
+ m_opaque_ap(new Address())
{
SetLoadAddress (load_addr, target);
}
@@ -68,7 +68,7 @@ SBAddress::operator = (const SBAddress &rhs)
if (rhs.IsValid())
ref() = rhs.ref();
else
- m_opaque_ap.reset();
+ m_opaque_ap.reset (new Address());
}
return *this;
}
@@ -82,7 +82,7 @@ SBAddress::IsValid () const
void
SBAddress::Clear ()
{
- m_opaque_ap.reset();
+ m_opaque_ap.reset (new Address());
}
void
@@ -100,13 +100,13 @@ SBAddress::SetAddress (const Address *lldb_object_ptr)
if (lldb_object_ptr)
ref() = *lldb_object_ptr;
else
- m_opaque_ap.reset();
+ m_opaque_ap.reset (new Address());
}
lldb::addr_t
SBAddress::GetFileAddress () const
{
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
return m_opaque_ap->GetFileAddress();
else
return LLDB_INVALID_ADDRESS;
@@ -121,7 +121,7 @@ SBAddress::GetLoadAddress (const SBTarget &target) const
TargetSP target_sp (target.GetSP());
if (target_sp)
{
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
addr = m_opaque_ap->GetLoadAddress (target_sp.get());
@@ -162,7 +162,7 @@ SBAddress::SetLoadAddress (lldb::addr_t load_addr, lldb::SBTarget &target)
bool
SBAddress::OffsetAddress (addr_t offset)
{
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
{
addr_t addr_offset = m_opaque_ap->GetOffset();
if (addr_offset != LLDB_INVALID_ADDRESS)
@@ -178,7 +178,7 @@ lldb::SBSection
SBAddress::GetSection ()
{
lldb::SBSection sb_section;
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
sb_section.SetSP (m_opaque_ap->GetSection());
return sb_section;
}
@@ -186,7 +186,7 @@ SBAddress::GetSection ()
lldb::addr_t
SBAddress::GetOffset ()
{
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
return m_opaque_ap->GetOffset();
return 0;
}
@@ -233,7 +233,7 @@ SBAddress::GetDescription (SBStream &description)
// Call "ref()" on the stream to make sure it creates a backing stream in
// case there isn't one already...
Stream &strm = description.ref();
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
{
m_opaque_ap->Dump (&strm,
NULL,
@@ -255,7 +255,7 @@ SBModule
SBAddress::GetModule ()
{
SBModule sb_module;
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
sb_module.SetSP (m_opaque_ap->GetModule());
return sb_module;
}
@@ -264,7 +264,7 @@ SBSymbolContext
SBAddress::GetSymbolContext (uint32_t resolve_scope)
{
SBSymbolContext sb_sc;
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
m_opaque_ap->CalculateSymbolContext (&sb_sc.ref(), resolve_scope);
return sb_sc;
}
@@ -273,7 +273,7 @@ SBCompileUnit
SBAddress::GetCompileUnit ()
{
SBCompileUnit sb_comp_unit;
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
sb_comp_unit.reset(m_opaque_ap->CalculateSymbolContextCompileUnit());
return sb_comp_unit;
}
@@ -282,7 +282,7 @@ SBFunction
SBAddress::GetFunction ()
{
SBFunction sb_function;
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
sb_function.reset(m_opaque_ap->CalculateSymbolContextFunction());
return sb_function;
}
@@ -291,7 +291,7 @@ SBBlock
SBAddress::GetBlock ()
{
SBBlock sb_block;
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
sb_block.SetPtr(m_opaque_ap->CalculateSymbolContextBlock());
return sb_block;
}
@@ -300,7 +300,7 @@ SBSymbol
SBAddress::GetSymbol ()
{
SBSymbol sb_symbol;
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
sb_symbol.reset(m_opaque_ap->CalculateSymbolContextSymbol());
return sb_symbol;
}
@@ -309,7 +309,7 @@ SBLineEntry
SBAddress::GetLineEntry ()
{
SBLineEntry sb_line_entry;
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
{
LineEntry line_entry;
if (m_opaque_ap->CalculateSymbolContextLineEntry (line_entry))
@@ -321,7 +321,7 @@ SBAddress::GetLineEntry ()
AddressClass
SBAddress::GetAddressClass ()
{
- if (m_opaque_ap.get())
+ if (m_opaque_ap->IsValid())
return m_opaque_ap->GetAddressClass();
return eAddressClassInvalid;
}
diff --git a/source/API/SBBreakpoint.cpp b/source/API/SBBreakpoint.cpp
index a950ca934c68..dd4c80caf45d 100644
--- a/source/API/SBBreakpoint.cpp
+++ b/source/API/SBBreakpoint.cpp
@@ -13,6 +13,7 @@
#include "lldb/API/SBEvent.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBStream.h"
+#include "lldb/API/SBStringList.h"
#include "lldb/API/SBThread.h"
#include "lldb/Breakpoint/Breakpoint.h"
@@ -653,6 +654,83 @@ SBBreakpoint::SetScriptCallbackBody (const char *callback_body_text)
return sb_error;
}
+bool
+SBBreakpoint::AddName (const char *new_name)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::AddName (name=%s)",
+ static_cast<void*>(m_opaque_sp.get()),
+ new_name);
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ Error error; // Think I'm just going to swallow the error here, it's probably more annoying to have to provide it.
+ return m_opaque_sp->AddName(new_name, error);
+ }
+
+ return false;
+}
+
+void
+SBBreakpoint::RemoveName (const char *name_to_remove)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::RemoveName (name=%s)",
+ static_cast<void*>(m_opaque_sp.get()),
+ name_to_remove);
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ m_opaque_sp->RemoveName(name_to_remove);
+ }
+}
+
+bool
+SBBreakpoint::MatchesName (const char *name)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::MatchesName (name=%s)",
+ static_cast<void*>(m_opaque_sp.get()),
+ name);
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ return m_opaque_sp->MatchesName(name);
+ }
+
+ return false;
+}
+
+void
+SBBreakpoint::GetNames (SBStringList &names)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::GetNames ()",
+ static_cast<void*>(m_opaque_sp.get()));
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ std::vector<std::string> names_vec;
+ m_opaque_sp->GetNames(names_vec);
+ for (std::string name : names_vec)
+ {
+ names.AppendString (name.c_str());
+ }
+ }
+}
+
lldb_private::Breakpoint *
SBBreakpoint::operator->() const
{
diff --git a/source/API/SBCommandInterpreter.cpp b/source/API/SBCommandInterpreter.cpp
index e1adea795b08..193d06e4d920 100644
--- a/source/API/SBCommandInterpreter.cpp
+++ b/source/API/SBCommandInterpreter.cpp
@@ -20,6 +20,7 @@
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBCommandReturnObject.h"
#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBExecutionContext.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBTarget.h"
#include "lldb/API/SBListener.h"
@@ -29,6 +30,100 @@
using namespace lldb;
using namespace lldb_private;
+SBCommandInterpreterRunOptions::SBCommandInterpreterRunOptions()
+{
+ m_opaque_up.reset(new CommandInterpreterRunOptions());
+}
+
+SBCommandInterpreterRunOptions::~SBCommandInterpreterRunOptions()
+{
+
+}
+
+bool
+SBCommandInterpreterRunOptions::GetStopOnContinue () const
+{
+ return m_opaque_up->GetStopOnContinue();
+}
+
+void
+SBCommandInterpreterRunOptions::SetStopOnContinue (bool stop_on_continue)
+{
+ m_opaque_up->SetStopOnContinue(stop_on_continue);
+}
+
+bool
+SBCommandInterpreterRunOptions::GetStopOnError () const
+{
+ return m_opaque_up->GetStopOnError();
+}
+
+void
+SBCommandInterpreterRunOptions::SetStopOnError (bool stop_on_error)
+{
+ m_opaque_up->SetStopOnError(stop_on_error);
+}
+
+bool
+SBCommandInterpreterRunOptions::GetStopOnCrash () const
+{
+ return m_opaque_up->GetStopOnCrash();
+}
+
+void
+SBCommandInterpreterRunOptions::SetStopOnCrash (bool stop_on_crash)
+{
+ m_opaque_up->SetStopOnCrash(stop_on_crash);
+}
+
+bool
+SBCommandInterpreterRunOptions::GetEchoCommands () const
+{
+ return m_opaque_up->GetEchoCommands();
+}
+
+void
+SBCommandInterpreterRunOptions::SetEchoCommands (bool echo_commands)
+{
+ m_opaque_up->SetEchoCommands(echo_commands);
+}
+
+bool
+SBCommandInterpreterRunOptions::GetPrintResults () const
+{
+ return m_opaque_up->GetPrintResults();
+}
+
+void
+SBCommandInterpreterRunOptions::SetPrintResults (bool print_results)
+{
+ m_opaque_up->SetPrintResults(print_results);
+}
+
+bool
+SBCommandInterpreterRunOptions::GetAddToHistory () const
+{
+ return m_opaque_up->GetAddToHistory();
+}
+
+void
+SBCommandInterpreterRunOptions::SetAddToHistory (bool add_to_history)
+{
+ m_opaque_up->SetAddToHistory(add_to_history);
+}
+
+lldb_private::CommandInterpreterRunOptions *
+SBCommandInterpreterRunOptions::get () const
+{
+ return m_opaque_up.get();
+}
+
+lldb_private::CommandInterpreterRunOptions &
+SBCommandInterpreterRunOptions::ref () const
+{
+ return *m_opaque_up.get();
+}
+
class CommandPluginInterfaceImplementation : public CommandObjectParsed
{
public:
@@ -128,6 +223,13 @@ SBCommandInterpreter::GetIOHandlerControlSequence(char ch)
lldb::ReturnStatus
SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnObject &result, bool add_to_history)
{
+ SBExecutionContext sb_exe_ctx;
+ return HandleCommand (command_line, sb_exe_ctx, result, add_to_history);
+}
+
+lldb::ReturnStatus
+SBCommandInterpreter::HandleCommand (const char *command_line, SBExecutionContext &override_context, SBCommandReturnObject &result, bool add_to_history)
+{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
@@ -135,11 +237,21 @@ SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnOb
static_cast<void*>(m_opaque_ptr), command_line,
static_cast<void*>(result.get()), add_to_history);
+ ExecutionContext ctx, *ctx_ptr;
+ if (override_context.get())
+ {
+ ctx = override_context.get()->Lock(true);
+ ctx_ptr = &ctx;
+ }
+ else
+ ctx_ptr = nullptr;
+
+
result.Clear();
if (command_line && m_opaque_ptr)
{
result.ref().SetInteractive(false);
- m_opaque_ptr->HandleCommand (command_line, add_to_history ? eLazyBoolYes : eLazyBoolNo, result.ref());
+ m_opaque_ptr->HandleCommand (command_line, add_to_history ? eLazyBoolYes : eLazyBoolNo, result.ref(), ctx_ptr);
}
else
{
@@ -162,6 +274,54 @@ SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnOb
return result.GetStatus();
}
+void
+SBCommandInterpreter::HandleCommandsFromFile (lldb::SBFileSpec &file,
+ lldb::SBExecutionContext &override_context,
+ lldb::SBCommandInterpreterRunOptions &options,
+ lldb::SBCommandReturnObject result)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ {
+ SBStream s;
+ file.GetDescription (s);
+ log->Printf ("SBCommandInterpreter(%p)::HandleCommandsFromFile (file=\"%s\", SBCommandReturnObject(%p))",
+ static_cast<void*>(m_opaque_ptr), s.GetData(),
+ static_cast<void*>(result.get()));
+ }
+
+ if (!m_opaque_ptr)
+ {
+ result->AppendError ("SBCommandInterpreter is not valid.");
+ result->SetStatus (eReturnStatusFailed);
+ return;
+ }
+
+ if (!file.IsValid())
+ {
+ SBStream s;
+ file.GetDescription (s);
+ result->AppendErrorWithFormat ("File is not valid: %s.", s.GetData());
+ result->SetStatus (eReturnStatusFailed);
+ }
+
+ FileSpec tmp_spec = file.ref();
+ ExecutionContext ctx, *ctx_ptr;
+ if (override_context.get())
+ {
+ ctx = override_context.get()->Lock(true);
+ ctx_ptr = &ctx;
+ }
+ else
+ ctx_ptr = nullptr;
+
+
+ m_opaque_ptr->HandleCommandsFromFile (tmp_spec, ctx_ptr, options.ref(), result.ref());
+
+}
+
+
int
SBCommandInterpreter::HandleCompletion (const char *current_line,
const char *cursor,
@@ -434,6 +594,7 @@ 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*
@@ -442,6 +603,17 @@ LLDBSwigPythonCreateSyntheticProvider (const char *python_class_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);
@@ -463,12 +635,16 @@ 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_private::CommandReturnObject &cmd_retobj,
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp);
extern "C" bool
LLDBSwigPythonCallModuleInit (const char *python_module_name,
@@ -504,6 +680,12 @@ LLDBSWIGPythonRunScriptKeywordFrame (const char* python_function_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,
@@ -532,6 +714,7 @@ SBCommandInterpreter::InitializeSWIG ()
LLDBSWIGPython_GetValueObjectSPFromSBValue,
LLDBSwigPython_UpdateSynthProviderInstance,
LLDBSwigPython_MightHaveChildrenSynthProviderInstance,
+ LLDBSwigPython_GetValueSynthProviderInstance,
LLDBSwigPythonCallCommand,
LLDBSwigPythonCallModuleInit,
LLDBSWIGPythonCreateOSPlugin,
@@ -539,7 +722,10 @@ SBCommandInterpreter::InitializeSWIG ()
LLDBSWIGPythonRunScriptKeywordThread,
LLDBSWIGPythonRunScriptKeywordTarget,
LLDBSWIGPythonRunScriptKeywordFrame,
- LLDBSWIGPython_GetDynamicSetting);
+ LLDBSWIGPythonRunScriptKeywordValue,
+ LLDBSWIGPython_GetDynamicSetting,
+ LLDBSwigPythonCreateScriptedThreadPlan,
+ LLDBSWIGPythonCallThreadPlan);
#endif
}
}
diff --git a/source/API/SBCommunication.cpp b/source/API/SBCommunication.cpp
index df0b864fad94..956b6cfcdd31 100644
--- a/source/API/SBCommunication.cpp
+++ b/source/API/SBCommunication.cpp
@@ -10,8 +10,8 @@
#include "lldb/API/SBCommunication.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/Core/Communication.h"
-#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Log.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
using namespace lldb;
using namespace lldb_private;
@@ -71,7 +71,7 @@ SBCommunication::Connect (const char *url)
if (m_opaque)
{
if (!m_opaque->HasConnection ())
- m_opaque->SetConnection (new ConnectionFileDescriptor());
+ m_opaque->SetConnection(Connection::CreateDefaultConnection(url));
return m_opaque->Connect (url, NULL);
}
return eConnectionStatusNoConnection;
diff --git a/source/API/SBCompileUnit.cpp b/source/API/SBCompileUnit.cpp
index 03c25710a9e4..5d904ce56300 100644
--- a/source/API/SBCompileUnit.cpp
+++ b/source/API/SBCompileUnit.cpp
@@ -228,6 +228,14 @@ SBCompileUnit::FindSupportFileIndex (uint32_t start_idx, const SBFileSpec &sb_fi
return 0;
}
+lldb::LanguageType
+SBCompileUnit::GetLanguage ()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->GetLanguage();
+ return lldb::eLanguageTypeUnknown;
+}
+
bool
SBCompileUnit::IsValid () const
{
diff --git a/source/API/SBDebugger.cpp b/source/API/SBDebugger.cpp
index dae567525a4a..a95f2ffc06d9 100644
--- a/source/API/SBDebugger.cpp
+++ b/source/API/SBDebugger.cpp
@@ -715,16 +715,13 @@ SBDebugger::CreateTarget (const char *filename)
TargetSP target_sp;
if (m_opaque_sp)
{
- ArchSpec arch = Target::GetDefaultArchitecture ();
Error error;
const bool add_dependent_modules = true;
-
- PlatformSP platform_sp(m_opaque_sp->GetPlatformList().GetSelectedPlatform());
- error = m_opaque_sp->GetTargetList().CreateTarget (*m_opaque_sp,
+ error = m_opaque_sp->GetTargetList().CreateTarget (*m_opaque_sp,
filename,
- arch,
+ NULL,
add_dependent_modules,
- platform_sp,
+ NULL,
target_sp);
if (error.Success())
@@ -972,7 +969,32 @@ SBDebugger::RunCommandInterpreter (bool auto_handle_events,
bool spawn_thread)
{
if (m_opaque_sp)
- m_opaque_sp->GetCommandInterpreter().RunCommandInterpreter(auto_handle_events, spawn_thread);
+ {
+ CommandInterpreterRunOptions options;
+
+ m_opaque_sp->GetCommandInterpreter().RunCommandInterpreter(auto_handle_events,
+ spawn_thread,
+ options);
+ }
+}
+
+void
+SBDebugger::RunCommandInterpreter (bool auto_handle_events,
+ bool spawn_thread,
+ SBCommandInterpreterRunOptions &options,
+ int &num_errors,
+ bool &quit_requested,
+ bool &stopped_for_crash)
+
+{
+ if (m_opaque_sp)
+ {
+ CommandInterpreter &interp = m_opaque_sp->GetCommandInterpreter();
+ interp.RunCommandInterpreter(auto_handle_events, spawn_thread, options.ref());
+ num_errors = interp.GetNumErrors();
+ quit_requested = interp.GetQuitRequested();
+ stopped_for_crash = interp.GetStoppedForCrash();
+ }
}
void
@@ -1186,19 +1208,42 @@ SBDebugger::GetID()
SBError
-SBDebugger::SetCurrentPlatform (const char *platform_name)
+SBDebugger::SetCurrentPlatform (const char *platform_name_cstr)
{
SBError sb_error;
if (m_opaque_sp)
{
- PlatformSP platform_sp (Platform::Create (platform_name, sb_error.ref()));
-
- if (platform_sp)
+ if (platform_name_cstr && platform_name_cstr[0])
{
- bool make_selected = true;
- m_opaque_sp->GetPlatformList().Append (platform_sp, make_selected);
+ ConstString platform_name (platform_name_cstr);
+ PlatformSP platform_sp (Platform::Find (platform_name));
+
+ if (platform_sp)
+ {
+ // Already have a platform with this name, just select it
+ m_opaque_sp->GetPlatformList().SetSelectedPlatform(platform_sp);
+ }
+ else
+ {
+ // We don't have a platform by this name yet, create one
+ platform_sp = Platform::Create (platform_name, sb_error.ref());
+ if (platform_sp)
+ {
+ // We created the platform, now append and select it
+ bool make_selected = true;
+ m_opaque_sp->GetPlatformList().Append (platform_sp, make_selected);
+ }
+ }
+ }
+ else
+ {
+ sb_error.ref().SetErrorString("invalid platform name");
}
}
+ else
+ {
+ sb_error.ref().SetErrorString("invalid debugger");
+ }
return sb_error;
}
diff --git a/source/API/SBEvent.cpp b/source/API/SBEvent.cpp
index 57a699fd739d..c62c495b87c8 100644
--- a/source/API/SBEvent.cpp
+++ b/source/API/SBEvent.cpp
@@ -43,6 +43,12 @@ SBEvent::SBEvent (EventSP &event_sp) :
{
}
+SBEvent::SBEvent (Event *event_ptr) :
+ m_event_sp (),
+ m_opaque_ptr (event_ptr)
+{
+}
+
SBEvent::SBEvent (const SBEvent &rhs) :
m_event_sp (rhs.m_event_sp),
m_opaque_ptr (rhs.m_opaque_ptr)
diff --git a/source/API/SBExecutionContext.cpp b/source/API/SBExecutionContext.cpp
new file mode 100644
index 000000000000..dc20c6092132
--- /dev/null
+++ b/source/API/SBExecutionContext.cpp
@@ -0,0 +1,129 @@
+//===-- SBExecutionContext.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/SBExecutionContext.h"
+
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBThread.h"
+#include "lldb/API/SBFrame.h"
+
+#include "lldb/Target/ExecutionContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBExecutionContext::SBExecutionContext() :
+m_exe_ctx_sp()
+{
+}
+
+SBExecutionContext::SBExecutionContext (const lldb::SBExecutionContext &rhs) :
+m_exe_ctx_sp(rhs.m_exe_ctx_sp)
+{
+}
+
+SBExecutionContext::SBExecutionContext (lldb::ExecutionContextRefSP exe_ctx_ref_sp) :
+m_exe_ctx_sp(exe_ctx_ref_sp)
+{
+}
+
+SBExecutionContext::SBExecutionContext (const lldb::SBTarget &target) :
+m_exe_ctx_sp(new ExecutionContextRef())
+{
+ m_exe_ctx_sp->SetTargetSP(target.GetSP());
+}
+
+SBExecutionContext::SBExecutionContext (const lldb::SBProcess &process) :
+m_exe_ctx_sp(new ExecutionContextRef())
+{
+ m_exe_ctx_sp->SetProcessSP(process.GetSP());
+}
+
+SBExecutionContext::SBExecutionContext (lldb::SBThread thread) :
+m_exe_ctx_sp(new ExecutionContextRef())
+{
+ m_exe_ctx_sp->SetThreadPtr(thread.get());
+}
+
+SBExecutionContext::SBExecutionContext (const lldb::SBFrame &frame) :
+m_exe_ctx_sp(new ExecutionContextRef())
+{
+ m_exe_ctx_sp->SetFrameSP(frame.GetFrameSP());
+}
+
+SBExecutionContext::~SBExecutionContext()
+{
+}
+
+const SBExecutionContext &
+SBExecutionContext::operator = (const lldb::SBExecutionContext &rhs)
+{
+ m_exe_ctx_sp = rhs.m_exe_ctx_sp;
+ return *this;
+}
+
+ExecutionContextRef *
+SBExecutionContext::get () const
+{
+ return m_exe_ctx_sp.get();
+}
+
+SBTarget
+SBExecutionContext::GetTarget () const
+{
+ SBTarget sb_target;
+ if (m_exe_ctx_sp)
+ {
+ TargetSP target_sp(m_exe_ctx_sp->GetTargetSP());
+ if (target_sp)
+ sb_target.SetSP(target_sp);
+ }
+ return sb_target;
+}
+
+SBProcess
+SBExecutionContext::GetProcess () const
+{
+ SBProcess sb_process;
+ if (m_exe_ctx_sp)
+ {
+ ProcessSP process_sp(m_exe_ctx_sp->GetProcessSP());
+ if (process_sp)
+ sb_process.SetSP(process_sp);
+ }
+ return sb_process;
+}
+
+SBThread
+SBExecutionContext::GetThread () const
+{
+ SBThread sb_thread;
+ if (m_exe_ctx_sp)
+ {
+ ThreadSP thread_sp(m_exe_ctx_sp->GetThreadSP());
+ if (thread_sp)
+ sb_thread.SetThread(thread_sp);
+ }
+ return sb_thread;
+}
+
+SBFrame
+SBExecutionContext::GetFrame () const
+{
+ SBFrame sb_frame;
+ if (m_exe_ctx_sp)
+ {
+ StackFrameSP frame_sp(m_exe_ctx_sp->GetFrameSP());
+ if (frame_sp)
+ sb_frame.SetFrameSP(frame_sp);
+ }
+ return sb_frame;
+}
+
diff --git a/source/API/SBFunction.cpp b/source/API/SBFunction.cpp
index 3d185da17f26..bf5e9180a437 100644
--- a/source/API/SBFunction.cpp
+++ b/source/API/SBFunction.cpp
@@ -227,5 +227,15 @@ SBFunction::GetBlock ()
return sb_block;
}
+lldb::LanguageType
+SBFunction::GetLanguage ()
+{
+ if (m_opaque_ptr)
+ {
+ if (m_opaque_ptr->GetCompileUnit())
+ return m_opaque_ptr->GetCompileUnit()->GetLanguage();
+ }
+ return lldb::eLanguageTypeUnknown;
+}
diff --git a/source/API/SBHostOS.cpp b/source/API/SBHostOS.cpp
index ec1e2f2e9cba..008ca4d9672e 100644
--- a/source/API/SBHostOS.cpp
+++ b/source/API/SBHostOS.cpp
@@ -13,6 +13,9 @@
#include "lldb/Core/Log.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/HostNativeThread.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/ThreadLauncher.h"
using namespace lldb;
using namespace lldb_private;
@@ -69,31 +72,54 @@ SBHostOS::ThreadCreate
// FIXME: You should log the return value?
- return Host::ThreadCreate (name, thread_function, thread_arg, error_ptr ? error_ptr->get() : NULL);
+ HostThread thread(ThreadLauncher::LaunchThread(name, thread_function, thread_arg, error_ptr ? error_ptr->get() : NULL));
+ return thread.Release();
}
void
SBHostOS::ThreadCreated (const char *name)
{
- Host::ThreadCreated (name);
}
bool
SBHostOS::ThreadCancel (lldb::thread_t thread, SBError *error_ptr)
{
- return Host::ThreadCancel (thread, error_ptr ? error_ptr->get() : NULL);
+ Error error;
+ HostThread host_thread(thread);
+ error = host_thread.Cancel();
+ if (error_ptr)
+ error_ptr->SetError(error);
+ host_thread.Release();
+ return error.Success();
}
bool
SBHostOS::ThreadDetach (lldb::thread_t thread, SBError *error_ptr)
{
- return Host::ThreadDetach (thread, error_ptr ? error_ptr->get() : NULL);
+ Error error;
+#if defined(_WIN32)
+ if (error_ptr)
+ error_ptr->SetErrorString("ThreadDetach is not supported on this platform");
+#else
+ HostThread host_thread(thread);
+ error = host_thread.GetNativeThread().Detach();
+ if (error_ptr)
+ error_ptr->SetError(error);
+ host_thread.Release();
+#endif
+ return error.Success();
}
bool
SBHostOS::ThreadJoin (lldb::thread_t thread, lldb::thread_result_t *result, SBError *error_ptr)
{
- return Host::ThreadJoin (thread, result, error_ptr ? error_ptr->get() : NULL);
+ Error error;
+ HostThread host_thread(thread);
+ error = host_thread.Join(result);
+ if (error_ptr)
+ error_ptr->SetError(error);
+ host_thread.Release();
+ return error.Success();
}
diff --git a/source/API/SBInstruction.cpp b/source/API/SBInstruction.cpp
index 2334cc0d124a..eccc4e29aadf 100644
--- a/source/API/SBInstruction.cpp
+++ b/source/API/SBInstruction.cpp
@@ -20,6 +20,7 @@
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/StackFrame.h"
@@ -170,9 +171,15 @@ SBInstruction::GetDescription (lldb::SBStream &s)
{
if (m_opaque_sp)
{
+ SymbolContext sc;
+ const Address &addr = m_opaque_sp->GetAddress();
+ ModuleSP module_sp (addr.GetModule());
+ if (module_sp)
+ module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
// Use the "ref()" instead of the "get()" accessor in case the SBStream
// didn't have a stream already created, one will get created...
- m_opaque_sp->Dump (&s.ref(), 0, true, false, NULL);
+ const char *disassemble_format = "${addr-file-or-load}: ";
+ m_opaque_sp->Dump (&s.ref(), 0, true, false, NULL, &sc, NULL, disassemble_format);
return true;
}
return false;
@@ -186,8 +193,14 @@ SBInstruction::Print (FILE *out)
if (m_opaque_sp)
{
+ SymbolContext sc;
+ const Address &addr = m_opaque_sp->GetAddress();
+ ModuleSP module_sp (addr.GetModule());
+ if (module_sp)
+ module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
StreamFile out_stream (out, false);
- m_opaque_sp->Dump (&out_stream, 0, true, false, NULL);
+ const char *disassemble_format = "${addr-file-or-load}: ";
+ m_opaque_sp->Dump (&out_stream, 0, true, false, NULL, &sc, NULL, disassemble_format);
}
}
diff --git a/source/API/SBInstructionList.cpp b/source/API/SBInstructionList.cpp
index fe22d9c29e4a..31585b3e6868 100644
--- a/source/API/SBInstructionList.cpp
+++ b/source/API/SBInstructionList.cpp
@@ -11,7 +11,9 @@
#include "lldb/API/SBInstruction.h"
#include "lldb/API/SBStream.h"
#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/SymbolContext.h"
using namespace lldb;
using namespace lldb_private;
@@ -100,12 +102,24 @@ SBInstructionList::GetDescription (lldb::SBStream &description)
// exist already inside description...
Stream &sref = description.ref();
const uint32_t max_opcode_byte_size = m_opaque_sp->GetInstructionList().GetMaxOpcocdeByteSize();
+ const char *disassemble_format = "${addr-file-or-load}: ";
+ SymbolContext sc;
+ SymbolContext prev_sc;
for (size_t i=0; i<num_instructions; ++i)
{
Instruction *inst = m_opaque_sp->GetInstructionList().GetInstructionAtIndex (i).get();
if (inst == NULL)
break;
- inst->Dump (&sref, max_opcode_byte_size, true, false, NULL);
+
+ const Address &addr = inst->GetAddress();
+ prev_sc = sc;
+ ModuleSP module_sp (addr.GetModule());
+ if (module_sp)
+ {
+ module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
+ }
+
+ inst->Dump (&sref, max_opcode_byte_size, true, false, NULL, &sc, &prev_sc, disassemble_format);
sref.EOL();
}
return true;
diff --git a/source/API/SBListener.cpp b/source/API/SBListener.cpp
index bad9ba82bc91..87318739a3a4 100644
--- a/source/API/SBListener.cpp
+++ b/source/API/SBListener.cpp
@@ -69,6 +69,12 @@ SBListener::SBListener (Listener &listener) :
{
}
+SBListener::SBListener (const lldb::ListenerSP &listener_sp) :
+ m_opaque_sp (listener_sp),
+ m_opaque_ptr (listener_sp.get())
+{
+}
+
SBListener::~SBListener ()
{
}
diff --git a/source/API/SBPlatform.cpp b/source/API/SBPlatform.cpp
index 9914852cead7..d3e769ae675b 100644
--- a/source/API/SBPlatform.cpp
+++ b/source/API/SBPlatform.cpp
@@ -269,7 +269,8 @@ SBPlatform::SBPlatform (const char *platform_name) :
m_opaque_sp ()
{
Error error;
- m_opaque_sp = Platform::Create (platform_name, error);
+ if (platform_name && platform_name[0])
+ m_opaque_sp = Platform::Create (ConstString(platform_name), error);
}
SBPlatform::~SBPlatform()
diff --git a/source/API/SBProcess.cpp b/source/API/SBProcess.cpp
index 41efd86177d6..9a0b23bc93d2 100644
--- a/source/API/SBProcess.cpp
+++ b/source/API/SBProcess.cpp
@@ -38,6 +38,7 @@
#include "lldb/API/SBEvent.h"
#include "lldb/API/SBFileSpec.h"
#include "lldb/API/SBThread.h"
+#include "lldb/API/SBThreadCollection.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBStringList.h"
#include "lldb/API/SBUnixSignals.h"
@@ -738,18 +739,10 @@ SBProcess::Continue ()
{
Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
- Error error (process_sp->Resume());
- if (error.Success())
- {
- if (process_sp->GetTarget().GetDebugger().GetAsyncExecution () == false)
- {
- if (log)
- log->Printf ("SBProcess(%p)::Continue () waiting for process to stop...",
- static_cast<void*>(process_sp.get()));
- process_sp->WaitForProcessToStop (NULL);
- }
- }
- sb_error.SetError(error);
+ if (process_sp->GetTarget().GetDebugger().GetAsyncExecution ())
+ sb_error.ref() = process_sp->Resume ();
+ else
+ sb_error.ref() = process_sp->ResumeSynchronous (NULL);
}
else
sb_error.SetErrorString ("SBProcess is invalid");
@@ -1381,3 +1374,30 @@ SBProcess::GetExtendedBacktraceTypeAtIndex (uint32_t idx)
}
return NULL;
}
+
+SBThreadCollection
+SBProcess::GetHistoryThreads (addr_t addr)
+{
+ ProcessSP process_sp(GetSP());
+ SBThreadCollection threads;
+ if (process_sp)
+ {
+ threads = SBThreadCollection(process_sp->GetHistoryThreads(addr));
+ }
+ return threads;
+}
+
+bool
+SBProcess::IsInstrumentationRuntimePresent(InstrumentationRuntimeType type)
+{
+ ProcessSP process_sp(GetSP());
+ if (! process_sp)
+ return false;
+
+ InstrumentationRuntimeSP runtime_sp = process_sp->GetInstrumentationRuntime(type);
+
+ if (! runtime_sp.get())
+ return false;
+
+ return runtime_sp->IsActive();
+}
diff --git a/source/API/SBSection.cpp b/source/API/SBSection.cpp
index 3fb84e81465c..809eca60c683 100644
--- a/source/API/SBSection.cpp
+++ b/source/API/SBSection.cpp
@@ -250,6 +250,14 @@ SBSection::GetSectionType ()
return eSectionTypeInvalid;
}
+uint32_t
+SBSection::GetTargetByteSize ()
+{
+ SectionSP section_sp (GetSP());
+ if (section_sp.get())
+ return section_sp->GetTargetByteSize();
+ return 0;
+}
bool
SBSection::operator == (const SBSection &rhs)
diff --git a/source/API/SBTarget.cpp b/source/API/SBTarget.cpp
index 3d5828c5fe00..b87b1acf45df 100644
--- a/source/API/SBTarget.cpp
+++ b/source/API/SBTarget.cpp
@@ -58,6 +58,7 @@
#include "lldb/Interpreter/CommandReturnObject.h"
#include "../source/Commands/CommandObjectBreakpoint.h"
+#include "llvm/Support/Regex.h"
using namespace lldb;
@@ -132,6 +133,18 @@ SBLaunchInfo::SetExecutableFile (SBFileSpec exe_file, bool add_as_first_arg)
m_opaque_sp->SetExecutableFile(exe_file.ref(), add_as_first_arg);
}
+SBListener
+SBLaunchInfo::GetListener ()
+{
+ return SBListener(m_opaque_sp->GetListener());
+}
+
+void
+SBLaunchInfo::SetListener (SBListener &listener)
+{
+ m_opaque_sp->SetListener(listener.GetSP());
+}
+
uint32_t
SBLaunchInfo::GetNumArguments ()
{
@@ -235,13 +248,16 @@ SBLaunchInfo::SetProcessPluginName (const char *plugin_name)
const char *
SBLaunchInfo::GetShell ()
{
- return m_opaque_sp->GetShell();
+ // Constify this string so that it is saved in the string pool. Otherwise
+ // it would be freed when this function goes out of scope.
+ ConstString shell(m_opaque_sp->GetShell().GetPath().c_str());
+ return shell.AsCString();
}
void
SBLaunchInfo::SetShell (const char * path)
{
- m_opaque_sp->SetShell (path);
+ m_opaque_sp->SetShell (FileSpec(path, false));
}
uint32_t
@@ -516,6 +532,17 @@ 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());
+}
//----------------------------------------------------------------------
// SBTarget constructor
@@ -583,6 +610,19 @@ SBTarget::GetProcess ()
return sb_process;
}
+SBPlatform
+SBTarget::GetPlatform ()
+{
+ TargetSP target_sp(GetSP());
+ if (!target_sp)
+ return SBPlatform();
+
+ SBPlatform platform;
+ platform.m_opaque_sp = target_sp->GetPlatform();
+
+ return platform;
+}
+
SBDebugger
SBTarget::GetDebugger () const
{
@@ -734,9 +774,9 @@ SBTarget::Launch
launch_info.GetEnvironmentEntries ().SetArguments (envp);
if (listener.IsValid())
- error.SetError (target_sp->Launch(listener.ref(), launch_info));
- else
- error.SetError (target_sp->Launch(target_sp->GetDebugger().GetListener(), launch_info));
+ launch_info.SetListener(listener.GetSP());
+
+ error.SetError (target_sp->Launch(launch_info, NULL));
sb_process.SetSP(target_sp->GetProcessSP());
}
@@ -800,7 +840,7 @@ SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error)
if (arch_spec.IsValid())
launch_info.GetArchitecture () = arch_spec;
- error.SetError (target_sp->Launch (target_sp->GetDebugger().GetListener(), launch_info));
+ error.SetError (target_sp->Launch (launch_info, NULL));
sb_process.SetSP(target_sp->GetProcessSP());
}
else
@@ -1000,7 +1040,7 @@ SBTarget::AttachToProcessWithID
// If we are doing synchronous mode, then wait for the
// process to stop!
if (target_sp->GetDebugger().GetAsyncExecution () == false)
- process_sp->WaitForProcessToStop (NULL);
+ process_sp->WaitForProcessToStop (NULL);
}
}
else
@@ -1227,6 +1267,22 @@ SBTarget::ResolveLoadAddress (lldb::addr_t vm_addr)
return sb_addr;
}
+lldb::SBAddress
+SBTarget::ResolveFileAddress (lldb::addr_t file_addr)
+{
+ lldb::SBAddress sb_addr;
+ Address &addr = sb_addr.ref();
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ if (target_sp->ResolveFileAddress (file_addr, addr))
+ return sb_addr;
+ }
+
+ addr.SetRawAddress(file_addr);
+ return sb_addr;
+}
lldb::SBAddress
SBTarget::ResolvePastLoadAddress (uint32_t stop_id, lldb::addr_t vm_addr)
@@ -1261,6 +1317,27 @@ SBTarget::ResolveSymbolContextForAddress (const SBAddress& addr,
return sc;
}
+size_t
+SBTarget::ReadMemory (const SBAddress addr,
+ void *buf,
+ size_t size,
+ lldb::SBError &error)
+{
+ SBError sb_error;
+ size_t bytes_read = 0;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ bytes_read = target_sp->ReadMemory(addr.ref(), false, buf, size, sb_error.ref());
+ }
+ else
+ {
+ sb_error.SetErrorString("invalid target");
+ }
+
+ return bytes_read;
+}
SBBreakpoint
SBTarget::BreakpointCreateByLocation (const char *file,
@@ -1868,30 +1945,10 @@ SBTarget::CreateValueFromAddress (const char *name, SBAddress addr, SBType type)
lldb::ValueObjectSP new_value_sp;
if (IsValid() && name && *name && addr.IsValid() && type.IsValid())
{
- lldb::addr_t address(addr.GetLoadAddress(*this));
- lldb::TypeImplSP type_impl_sp (type.GetSP());
- ClangASTType pointer_ast_type(type_impl_sp->GetClangASTType(true).GetPointerType ());
- if (pointer_ast_type)
- {
- lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&address,sizeof(lldb::addr_t)));
-
- ExecutionContext exe_ctx (ExecutionContextRef(ExecutionContext(m_opaque_sp.get(),false)));
- ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
- pointer_ast_type,
- ConstString(name),
- buffer,
- exe_ctx.GetByteOrder(),
- exe_ctx.GetAddressByteSize()));
-
- if (ptr_result_valobj_sp)
- {
- ptr_result_valobj_sp->GetValue().SetValueType(Value::eValueTypeLoadAddress);
- Error err;
- new_value_sp = ptr_result_valobj_sp->Dereference(err);
- if (new_value_sp)
- new_value_sp->SetName(ConstString(name));
- }
- }
+ lldb::addr_t load_addr(addr.GetLoadAddress(*this));
+ ExecutionContext exe_ctx (ExecutionContextRef(ExecutionContext(m_opaque_sp.get(),false)));
+ ClangASTType ast_type(type.GetSP()->GetClangASTType(true));
+ new_value_sp = ValueObject::CreateValueObjectFromAddress(name, load_addr, exe_ctx, ast_type);
}
sb_value.SetSP(new_value_sp);
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
@@ -1908,6 +1965,58 @@ SBTarget::CreateValueFromAddress (const char *name, SBAddress addr, SBType type)
return sb_value;
}
+lldb::SBValue
+SBTarget::CreateValueFromData (const char *name, lldb::SBData data, lldb::SBType type)
+{
+ SBValue sb_value;
+ lldb::ValueObjectSP new_value_sp;
+ if (IsValid() && name && *name && data.IsValid() && type.IsValid())
+ {
+ DataExtractorSP extractor(*data);
+ ExecutionContext exe_ctx (ExecutionContextRef(ExecutionContext(m_opaque_sp.get(),false)));
+ ClangASTType ast_type(type.GetSP()->GetClangASTType(true));
+ new_value_sp = ValueObject::CreateValueObjectFromData(name, *extractor, exe_ctx, ast_type);
+ }
+ sb_value.SetSP(new_value_sp);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (new_value_sp)
+ log->Printf ("SBTarget(%p)::CreateValueFromData => \"%s\"",
+ static_cast<void*>(m_opaque_sp.get()),
+ new_value_sp->GetName().AsCString());
+ else
+ log->Printf ("SBTarget(%p)::CreateValueFromData => NULL",
+ static_cast<void*>(m_opaque_sp.get()));
+ }
+ return sb_value;
+}
+
+lldb::SBValue
+SBTarget::CreateValueFromExpression (const char *name, const char* expr)
+{
+ SBValue sb_value;
+ lldb::ValueObjectSP new_value_sp;
+ if (IsValid() && name && *name && expr && *expr)
+ {
+ ExecutionContext exe_ctx (ExecutionContextRef(ExecutionContext(m_opaque_sp.get(),false)));
+ new_value_sp = ValueObject::CreateValueObjectFromExpression(name, expr, exe_ctx);
+ }
+ sb_value.SetSP(new_value_sp);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (new_value_sp)
+ log->Printf ("SBTarget(%p)::CreateValueFromExpression => \"%s\"",
+ static_cast<void*>(m_opaque_sp.get()),
+ new_value_sp->GetName().AsCString());
+ else
+ log->Printf ("SBTarget(%p)::CreateValueFromExpression => NULL",
+ static_cast<void*>(m_opaque_sp.get()));
+ }
+ return sb_value;
+}
+
bool
SBTarget::DeleteAllWatchpoints ()
{
@@ -2057,6 +2166,28 @@ SBTarget::GetTriple ()
}
uint32_t
+SBTarget::GetDataByteSize ()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ return target_sp->GetArchitecture().GetDataByteSize() ;
+ }
+ return 0;
+}
+
+uint32_t
+SBTarget::GetCodeByteSize ()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ return target_sp->GetArchitecture().GetCodeByteSize() ;
+ }
+ return 0;
+}
+
+uint32_t
SBTarget::GetAddressByteSize()
{
TargetSP target_sp(GetSP());
@@ -2154,6 +2285,34 @@ SBTarget::FindFunctions (const char *name, uint32_t name_type_mask)
return sb_sc_list;
}
+lldb::SBSymbolContextList
+SBTarget::FindGlobalFunctions(const char *name, uint32_t max_matches, MatchType matchtype)
+{
+ lldb::SBSymbolContextList sb_sc_list;
+ if (name && name[0])
+ {
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ std::string regexstr;
+ switch (matchtype)
+ {
+ case eMatchTypeRegex:
+ target_sp->GetImages().FindFunctions(RegularExpression(name), true, true, true, *sb_sc_list);
+ break;
+ case eMatchTypeStartsWith:
+ regexstr = llvm::Regex::escape(name) + ".*";
+ target_sp->GetImages().FindFunctions(RegularExpression(regexstr.c_str()), true, true, true, *sb_sc_list);
+ break;
+ default:
+ target_sp->GetImages().FindFunctions(ConstString(name), eFunctionNameTypeAny, true, true, true, *sb_sc_list);
+ break;
+ }
+ }
+ }
+ return sb_sc_list;
+}
+
lldb::SBType
SBTarget::FindFirstType (const char* typename_cstr)
{
@@ -2188,14 +2347,19 @@ SBTarget::FindFirstType (const char* typename_cstr)
if (objc_language_runtime)
{
- TypeVendor *objc_type_vendor = objc_language_runtime->GetTypeVendor();
+ DeclVendor *objc_decl_vendor = objc_language_runtime->GetDeclVendor();
- if (objc_type_vendor)
+ if (objc_decl_vendor)
{
- std::vector <ClangASTType> types;
+ std::vector <clang::NamedDecl *> decls;
- if (objc_type_vendor->FindTypes(const_typename, true, 1, types) > 0)
- return SBType(types[0]);
+ if (objc_decl_vendor->FindDecls(const_typename, true, 1, decls) > 0)
+ {
+ if (ClangASTType type = ClangASTContext::GetTypeForDecl(decls[0]))
+ {
+ return SBType(type);
+ }
+ }
}
}
}
@@ -2261,17 +2425,20 @@ SBTarget::FindTypes (const char* typename_cstr)
if (objc_language_runtime)
{
- TypeVendor *objc_type_vendor = objc_language_runtime->GetTypeVendor();
+ DeclVendor *objc_decl_vendor = objc_language_runtime->GetDeclVendor();
- if (objc_type_vendor)
+ if (objc_decl_vendor)
{
- std::vector <ClangASTType> types;
+ std::vector <clang::NamedDecl *> decls;
- if (objc_type_vendor->FindTypes(const_typename, true, UINT32_MAX, types))
+ if (objc_decl_vendor->FindDecls(const_typename, true, 1, decls) > 0)
{
- for (ClangASTType &type : types)
+ for (clang::NamedDecl *decl : decls)
{
- sb_type_list.Append(SBType(type));
+ if (ClangASTType type = ClangASTContext::GetTypeForDecl(decl))
+ {
+ sb_type_list.Append(SBType(type));
+ }
}
}
}
@@ -2321,6 +2488,61 @@ SBTarget::FindGlobalVariables (const char *name, uint32_t max_matches)
return sb_value_list;
}
+SBValueList
+SBTarget::FindGlobalVariables(const char *name, uint32_t max_matches, MatchType matchtype)
+{
+ SBValueList sb_value_list;
+
+ TargetSP target_sp(GetSP());
+ if (name && target_sp)
+ {
+ VariableList variable_list;
+ const bool append = true;
+
+ std::string regexstr;
+ uint32_t match_count;
+ switch (matchtype)
+ {
+ case eMatchTypeNormal:
+ match_count = target_sp->GetImages().FindGlobalVariables(ConstString(name),
+ append,
+ max_matches,
+ variable_list);
+ break;
+ case eMatchTypeRegex:
+ match_count = target_sp->GetImages().FindGlobalVariables(RegularExpression(name),
+ append,
+ max_matches,
+ variable_list);
+ break;
+ case eMatchTypeStartsWith:
+ regexstr = llvm::Regex::escape(name) + ".*";
+ match_count = target_sp->GetImages().FindGlobalVariables(RegularExpression(regexstr.c_str()),
+ append,
+ max_matches,
+ variable_list);
+ break;
+ }
+
+
+ if (match_count > 0)
+ {
+ ExecutionContextScope *exe_scope = target_sp->GetProcessSP().get();
+ if (exe_scope == NULL)
+ exe_scope = target_sp.get();
+ for (uint32_t i = 0; i<match_count; ++i)
+ {
+ lldb::ValueObjectSP valobj_sp(ValueObjectVariable::Create(exe_scope, variable_list.GetVariableAtIndex(i)));
+ if (valobj_sp)
+ sb_value_list.Append(SBValue(valobj_sp));
+ }
+ }
+ }
+
+ return sb_value_list;
+}
+
+
lldb::SBValue
SBTarget::FindFirstGlobalVariable (const char* name)
{
diff --git a/source/API/SBThread.cpp b/source/API/SBThread.cpp
index a0bfa4313535..6524d10fb705 100644
--- a/source/API/SBThread.cpp
+++ b/source/API/SBThread.cpp
@@ -41,6 +41,7 @@
#include "lldb/API/SBEvent.h"
#include "lldb/API/SBFrame.h"
#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBThreadPlan.h"
#include "lldb/API/SBValue.h"
using namespace lldb;
@@ -194,6 +195,7 @@ SBThread::GetStopReasonDataCount ()
case eStopReasonExec:
case eStopReasonPlanComplete:
case eStopReasonThreadExiting:
+ case eStopReasonInstrumentation:
// There is no data for these stop reasons.
return 0;
@@ -254,6 +256,7 @@ SBThread::GetStopReasonDataAtIndex (uint32_t idx)
case eStopReasonExec:
case eStopReasonPlanComplete:
case eStopReasonThreadExiting:
+ case eStopReasonInstrumentation:
// There is no data for these stop reasons.
return 0;
@@ -305,6 +308,26 @@ SBThread::GetStopReasonDataAtIndex (uint32_t idx)
return 0;
}
+bool
+SBThread::GetStopReasonExtendedInfoAsJSON (lldb::SBStream &stream)
+{
+ Stream &strm = stream.ref();
+
+ ExecutionContext exe_ctx (m_opaque_sp.get());
+ if (! exe_ctx.HasThreadScope())
+ return false;
+
+
+ StopInfoSP stop_info = exe_ctx.GetThreadPtr()->GetStopInfo();
+ StructuredData::ObjectSP info = stop_info->GetExtendedInfo();
+ if (! info)
+ return false;
+
+ info->Dump(strm);
+
+ return true;
+}
+
size_t
SBThread::GetStopDescription (char *dst, size_t dst_len)
{
@@ -687,15 +710,11 @@ SBThread::ResumeNewPlan (ExecutionContext &exe_ctx, ThreadPlan *new_plan)
// Why do we need to set the current thread by ID here???
process->GetThreadList().SetSelectedThreadByID (thread->GetID());
- sb_error.ref() = process->Resume();
-
- if (sb_error.Success())
- {
- // If we are doing synchronous mode, then wait for the
- // process to stop yet again!
- if (process->GetTarget().GetDebugger().GetAsyncExecution () == false)
- process->WaitForProcessToStop (NULL);
- }
+
+ if (process->GetTarget().GetDebugger().GetAsyncExecution ())
+ sb_error.ref() = process->Resume ();
+ else
+ sb_error.ref() = process->ResumeSynchronous (NULL);
return sb_error;
}
@@ -918,7 +937,9 @@ SBThread::RunToAddress (lldb::addr_t addr)
Thread *thread = exe_ctx.GetThreadPtr();
- ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads));
+ ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress (abort_other_plans,
+ target_addr,
+ stop_other_threads));
// This returns an error, we should use it!
ResumeNewPlan (exe_ctx, new_plan_sp.get());
@@ -1073,6 +1094,46 @@ SBThread::StepOverUntil (lldb::SBFrame &sb_frame,
}
SBError
+SBThread::StepUsingScriptedThreadPlan (const char *script_class_name)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBError sb_error;
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (log)
+ {
+ log->Printf ("SBThread(%p)::StepUsingScriptedThreadPlan: class name: %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ script_class_name);
+ }
+
+
+ if (!exe_ctx.HasThreadScope())
+ {
+ sb_error.SetErrorString("this SBThread object is invalid");
+ return sb_error;
+ }
+
+ Thread *thread = exe_ctx.GetThreadPtr();
+ ThreadPlanSP thread_plan_sp = thread->QueueThreadPlanForStepScripted(false, script_class_name, false);
+
+ if (thread_plan_sp)
+ sb_error = ResumeNewPlan(exe_ctx, thread_plan_sp.get());
+ else
+ {
+ sb_error.SetErrorStringWithFormat("Error queuing thread plan for class: %s.", script_class_name);
+ if (log)
+ log->Printf ("SBThread(%p)::StepUsingScriptedThreadPlan: Error queuing thread plan for class: %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ script_class_name);
+ }
+
+ return sb_error;
+}
+
+SBError
SBThread::JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
@@ -1473,7 +1534,8 @@ SBThread::GetExtendedBacktraceThread (const char *type)
const char *queue_name = new_thread_sp->GetQueueName();
if (queue_name == NULL)
queue_name = "";
- log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => new extended Thread created (%p) with queue_id 0x%" PRIx64 " queue name '%s'",
+ log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => new extended Thread "
+ "created (%p) with queue_id 0x%" PRIx64 " queue name '%s'",
static_cast<void*>(exe_ctx.GetThreadPtr()),
static_cast<void*>(new_thread_sp.get()),
new_thread_sp->GetQueueID(),
@@ -1515,3 +1577,24 @@ SBThread::SafeToCallFunctions ()
return thread_sp->SafeToCallFunctions();
return true;
}
+
+lldb_private::Thread *
+SBThread::operator->()
+{
+ ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
+ if (thread_sp)
+ return thread_sp.get();
+ else
+ return NULL;
+}
+
+lldb_private::Thread *
+SBThread::get()
+{
+ ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
+ if (thread_sp)
+ return thread_sp.get();
+ else
+ return NULL;
+}
+
diff --git a/source/API/SBThreadCollection.cpp b/source/API/SBThreadCollection.cpp
new file mode 100644
index 000000000000..841f93253a53
--- /dev/null
+++ b/source/API/SBThreadCollection.cpp
@@ -0,0 +1,97 @@
+//===-- SBThreadCollection.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/SBThreadCollection.h"
+#include "lldb/API/SBThread.h"
+#include "lldb/Target/ThreadList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBThreadCollection::SBThreadCollection () :
+ m_opaque_sp()
+{
+}
+
+SBThreadCollection::SBThreadCollection(const SBThreadCollection &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+}
+
+const SBThreadCollection &
+SBThreadCollection::operator = (const SBThreadCollection &rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+SBThreadCollection::SBThreadCollection (const ThreadCollectionSP &threads) :
+ m_opaque_sp(threads)
+{
+}
+
+SBThreadCollection::~SBThreadCollection ()
+{
+}
+
+void
+SBThreadCollection::SetOpaque (const lldb::ThreadCollectionSP &threads)
+{
+ m_opaque_sp = threads;
+}
+
+lldb_private::ThreadCollection *
+SBThreadCollection::get() const
+{
+ return m_opaque_sp.get();
+}
+
+lldb_private::ThreadCollection *
+SBThreadCollection::operator->() const
+{
+ return m_opaque_sp.operator->();
+}
+
+lldb::ThreadCollectionSP &
+SBThreadCollection::operator*()
+{
+ return m_opaque_sp;
+}
+
+const lldb::ThreadCollectionSP &
+SBThreadCollection::operator*() const
+{
+ return m_opaque_sp;
+}
+
+
+bool
+SBThreadCollection::IsValid () const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+size_t
+SBThreadCollection::GetSize ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetSize();
+ return 0;
+}
+
+SBThread
+SBThreadCollection::GetThreadAtIndex(size_t idx)
+{
+ SBThread thread;
+ if (m_opaque_sp && idx < m_opaque_sp->GetSize())
+ thread = m_opaque_sp->GetThreadAtIndex(idx);
+ return thread;
+}
diff --git a/source/API/SBThreadPlan.cpp b/source/API/SBThreadPlan.cpp
new file mode 100644
index 000000000000..02b1a8d893b6
--- /dev/null
+++ b/source/API/SBThreadPlan.cpp
@@ -0,0 +1,285 @@
+//===-- SBThread.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/API/SBThread.h"
+
+#include "lldb/API/SBSymbolContext.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/SystemRuntime.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Queue.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanPython.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepRange.h"
+#include "lldb/Target/ThreadPlanStepInRange.h"
+
+
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBThreadPlan.h"
+#include "lldb/API/SBValue.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Constructors
+//----------------------------------------------------------------------
+SBThreadPlan::SBThreadPlan ()
+{
+}
+
+SBThreadPlan::SBThreadPlan (const ThreadPlanSP& lldb_object_sp) :
+ m_opaque_sp (lldb_object_sp)
+{
+}
+
+SBThreadPlan::SBThreadPlan (const SBThreadPlan &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+
+}
+
+SBThreadPlan::SBThreadPlan (lldb::SBThread &sb_thread, const char *class_name)
+{
+ Thread *thread = sb_thread.get();
+ if (thread)
+ m_opaque_sp.reset(new ThreadPlanPython(*thread, class_name));
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+
+const lldb::SBThreadPlan &
+SBThreadPlan::operator = (const SBThreadPlan &rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SBThreadPlan::~SBThreadPlan()
+{
+}
+
+lldb_private::ThreadPlan *
+SBThreadPlan::get()
+{
+ return m_opaque_sp.get();
+}
+
+bool
+SBThreadPlan::IsValid() const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+void
+SBThreadPlan::Clear ()
+{
+ m_opaque_sp.reset();
+}
+
+lldb::StopReason
+SBThreadPlan::GetStopReason()
+{
+ return eStopReasonNone;
+}
+
+size_t
+SBThreadPlan::GetStopReasonDataCount()
+{
+ return 0;
+}
+
+uint64_t
+SBThreadPlan::GetStopReasonDataAtIndex(uint32_t idx)
+{
+ return 0;
+}
+
+SBThread
+SBThreadPlan::GetThread () const
+{
+ if (m_opaque_sp)
+ {
+ return SBThread(m_opaque_sp->GetThread().shared_from_this());
+ }
+ else
+ return SBThread();
+}
+
+bool
+SBThreadPlan::GetDescription (lldb::SBStream &description) const
+{
+ if (m_opaque_sp)
+ {
+ m_opaque_sp->GetDescription(description.get(), eDescriptionLevelFull);
+ }
+ else
+ {
+ description.Printf("Empty SBThreadPlan");
+ }
+ return true;
+}
+
+void
+SBThreadPlan::SetThreadPlan (const ThreadPlanSP& lldb_object_sp)
+{
+ m_opaque_sp = lldb_object_sp;
+}
+
+void
+SBThreadPlan::SetPlanComplete (bool success)
+{
+ if (m_opaque_sp)
+ m_opaque_sp->SetPlanComplete (success);
+}
+
+bool
+SBThreadPlan::IsPlanComplete()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->IsPlanComplete();
+ else
+ return true;
+}
+
+bool
+SBThreadPlan::IsValid()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->ValidatePlan(nullptr);
+ else
+ return false;
+}
+
+ // This section allows an SBThreadPlan to push another of the common types of plans...
+ //
+ // FIXME, you should only be able to queue thread plans from inside the methods of a
+ // Scripted Thread Plan. Need a way to enforce that.
+
+SBThreadPlan
+SBThreadPlan::QueueThreadPlanForStepOverRange (SBAddress &sb_start_address,
+ lldb::addr_t size)
+{
+ if (m_opaque_sp)
+ {
+ Address *start_address = sb_start_address.get();
+ if (!start_address)
+ {
+ return SBThreadPlan();
+ }
+
+ AddressRange range (*start_address, size);
+ SymbolContext sc;
+ start_address->CalculateSymbolContext(&sc);
+ return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange (false,
+ range,
+ sc,
+ eAllThreads));
+ }
+ else
+ {
+ return SBThreadPlan();
+ }
+}
+
+SBThreadPlan
+SBThreadPlan::QueueThreadPlanForStepInRange (SBAddress &sb_start_address,
+ lldb::addr_t size)
+{
+ if (m_opaque_sp)
+ {
+ Address *start_address = sb_start_address.get();
+ if (!start_address)
+ {
+ return SBThreadPlan();
+ }
+
+ AddressRange range (*start_address, size);
+ SymbolContext sc;
+ start_address->CalculateSymbolContext(&sc);
+ return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForStepInRange (false,
+ range,
+ sc,
+ NULL,
+ eAllThreads));
+ }
+ else
+ {
+ return SBThreadPlan();
+ }
+}
+
+SBThreadPlan
+SBThreadPlan::QueueThreadPlanForStepOut (uint32_t frame_idx_to_step_to, bool first_insn)
+{
+ if (m_opaque_sp)
+ {
+ SymbolContext sc;
+ sc = m_opaque_sp->GetThread().GetStackFrameAtIndex(0)->GetSymbolContext(lldb::eSymbolContextEverything);
+ return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForStepOut (false,
+ &sc,
+ first_insn,
+ false,
+ eVoteYes,
+ eVoteNoOpinion,
+ frame_idx_to_step_to));
+ }
+ else
+ {
+ return SBThreadPlan();
+ }
+}
+
+SBThreadPlan
+SBThreadPlan::QueueThreadPlanForRunToAddress (SBAddress sb_address)
+{
+ if (m_opaque_sp)
+ {
+ Address *address = sb_address.get();
+ if (!address)
+ return SBThreadPlan();
+
+ return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress (false,
+ *address,
+ false));
+ }
+ else
+ {
+ return SBThreadPlan();
+ }
+}
+
+
diff --git a/source/API/SBType.cpp b/source/API/SBType.cpp
index 064fb32c953f..8a0f5d848a3d 100644
--- a/source/API/SBType.cpp
+++ b/source/API/SBType.cpp
@@ -156,6 +156,14 @@ SBType::IsPointerType()
}
bool
+SBType::IsArrayType()
+{
+ if (!IsValid())
+ return false;
+ return m_opaque_sp->GetClangASTType(true).IsArrayType(nullptr, nullptr, nullptr);
+}
+
+bool
SBType::IsReferenceType()
{
if (!IsValid())
@@ -204,6 +212,14 @@ SBType::GetDereferencedType()
return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetDereferencedType())));
}
+SBType
+SBType::GetArrayElementType()
+{
+ if (!IsValid())
+ return SBType();
+ return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetClangASTType(true).GetArrayElementType())));
+}
+
bool
SBType::IsFunctionType ()
{
@@ -220,7 +236,13 @@ SBType::IsPolymorphicClass ()
return m_opaque_sp->GetClangASTType(true).IsPolymorphicClass();
}
-
+bool
+SBType::IsTypedefType ()
+{
+ if (!IsValid())
+ return false;
+ return m_opaque_sp->GetClangASTType(true).IsTypedefType();
+}
lldb::SBType
SBType::GetFunctionReturnType ()
@@ -252,6 +274,25 @@ SBType::GetFunctionArgumentTypes ()
return sb_type_list;
}
+uint32_t
+SBType::GetNumberOfMemberFunctions ()
+{
+ if (IsValid())
+ {
+ return m_opaque_sp->GetClangASTType(true).GetNumMemberFunctions();
+ }
+ return 0;
+}
+
+lldb::SBTypeMemberFunction
+SBType::GetMemberFunctionAtIndex (uint32_t idx)
+{
+ SBTypeMemberFunction sb_func_type;
+ if (IsValid())
+ sb_func_type.reset(new TypeMemberFunctionImpl(m_opaque_sp->GetClangASTType(true).GetMemberFunctionAtIndex(idx)));
+ return sb_func_type;
+}
+
lldb::SBType
SBType::GetUnqualifiedType()
{
@@ -305,7 +346,7 @@ uint32_t
SBType::GetNumberOfFields ()
{
if (IsValid())
- return m_opaque_sp->GetClangASTType(false).GetNumFields();
+ return m_opaque_sp->GetClangASTType(true).GetNumFields();
return 0;
}
@@ -430,6 +471,14 @@ SBType::IsTypeComplete()
return m_opaque_sp->GetClangASTType(false).IsCompleteType();
}
+uint32_t
+SBType::GetTypeFlags ()
+{
+ if (!IsValid())
+ return 0;
+ return m_opaque_sp->GetClangASTType(true).GetTypeInfo();
+}
+
const char*
SBType::GetName()
{
@@ -450,7 +499,7 @@ lldb::TypeClass
SBType::GetTypeClass ()
{
if (IsValid())
- return m_opaque_sp->GetClangASTType(false).GetTypeClass();
+ return m_opaque_sp->GetClangASTType(true).GetTypeClass();
return lldb::eTypeClassInvalid;
}
@@ -684,3 +733,121 @@ SBTypeMember::ref () const
{
return *m_opaque_ap.get();
}
+
+SBTypeMemberFunction::SBTypeMemberFunction() :
+m_opaque_sp()
+{
+}
+
+SBTypeMemberFunction::~SBTypeMemberFunction()
+{
+}
+
+SBTypeMemberFunction::SBTypeMemberFunction (const SBTypeMemberFunction& rhs) :
+ m_opaque_sp(rhs.m_opaque_sp)
+{
+}
+
+lldb::SBTypeMemberFunction&
+SBTypeMemberFunction::operator = (const lldb::SBTypeMemberFunction& rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+bool
+SBTypeMemberFunction::IsValid() const
+{
+ return m_opaque_sp.get();
+}
+
+const char *
+SBTypeMemberFunction::GetName ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetName().GetCString();
+ return NULL;
+}
+
+SBType
+SBTypeMemberFunction::GetType ()
+{
+ SBType sb_type;
+ if (m_opaque_sp)
+ {
+ sb_type.SetSP(lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetType())));
+ }
+ return sb_type;
+}
+
+lldb::SBType
+SBTypeMemberFunction::GetReturnType ()
+{
+ SBType sb_type;
+ if (m_opaque_sp)
+ {
+ sb_type.SetSP(lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetReturnType())));
+ }
+ return sb_type;
+}
+
+uint32_t
+SBTypeMemberFunction::GetNumberOfArguments ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetNumArguments();
+ return 0;
+}
+
+lldb::SBType
+SBTypeMemberFunction::GetArgumentTypeAtIndex (uint32_t i)
+{
+ SBType sb_type;
+ if (m_opaque_sp)
+ {
+ sb_type.SetSP(lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetArgumentAtIndex(i))));
+ }
+ return sb_type;
+}
+
+lldb::MemberFunctionKind
+SBTypeMemberFunction::GetKind ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetKind();
+ return lldb::eMemberFunctionKindUnknown;
+
+}
+
+bool
+SBTypeMemberFunction::GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_sp)
+ return m_opaque_sp->GetDescription(strm);
+
+ return false;
+}
+
+void
+SBTypeMemberFunction::reset(TypeMemberFunctionImpl *type_member_impl)
+{
+ m_opaque_sp.reset(type_member_impl);
+}
+
+TypeMemberFunctionImpl &
+SBTypeMemberFunction::ref ()
+{
+ if (!m_opaque_sp)
+ m_opaque_sp.reset (new TypeMemberFunctionImpl());
+ return *m_opaque_sp.get();
+}
+
+const TypeMemberFunctionImpl &
+SBTypeMemberFunction::ref () const
+{
+ return *m_opaque_sp.get();
+}
diff --git a/source/API/SBTypeSummary.cpp b/source/API/SBTypeSummary.cpp
index aaa09c289cb1..8a235bf50080 100644
--- a/source/API/SBTypeSummary.cpp
+++ b/source/API/SBTypeSummary.cpp
@@ -20,6 +20,103 @@ using namespace lldb_private;
#ifndef LLDB_DISABLE_PYTHON
+SBTypeSummaryOptions::SBTypeSummaryOptions()
+{
+ m_opaque_ap.reset(new TypeSummaryOptions());
+}
+
+SBTypeSummaryOptions::SBTypeSummaryOptions (const lldb::SBTypeSummaryOptions &rhs)
+{
+ if (rhs.m_opaque_ap)
+ m_opaque_ap.reset(new TypeSummaryOptions(*rhs.m_opaque_ap.get()));
+ else
+ m_opaque_ap.reset(new TypeSummaryOptions());
+}
+
+SBTypeSummaryOptions::~SBTypeSummaryOptions ()
+{
+}
+
+bool
+SBTypeSummaryOptions::IsValid()
+{
+ return m_opaque_ap.get();
+}
+
+lldb::LanguageType
+SBTypeSummaryOptions::GetLanguage ()
+{
+ if (IsValid())
+ return m_opaque_ap->GetLanguage();
+ return lldb::eLanguageTypeUnknown;
+}
+
+lldb::TypeSummaryCapping
+SBTypeSummaryOptions::GetCapping ()
+{
+ if (IsValid())
+ return m_opaque_ap->GetCapping();
+ return eTypeSummaryCapped;
+}
+
+void
+SBTypeSummaryOptions::SetLanguage (lldb::LanguageType l)
+{
+ if (IsValid())
+ m_opaque_ap->SetLanguage(l);
+}
+
+void
+SBTypeSummaryOptions::SetCapping (lldb::TypeSummaryCapping c)
+{
+ if (IsValid())
+ m_opaque_ap->SetCapping(c);
+}
+
+lldb_private::TypeSummaryOptions *
+SBTypeSummaryOptions::operator->()
+{
+ return m_opaque_ap.get();
+}
+
+const lldb_private::TypeSummaryOptions *
+SBTypeSummaryOptions::operator->() const
+{
+ return m_opaque_ap.get();
+}
+
+lldb_private::TypeSummaryOptions *
+SBTypeSummaryOptions::get ()
+{
+ return m_opaque_ap.get();
+}
+
+lldb_private::TypeSummaryOptions &
+SBTypeSummaryOptions::ref()
+{
+ return *m_opaque_ap.get();
+}
+
+const lldb_private::TypeSummaryOptions &
+SBTypeSummaryOptions::ref() const
+{
+ return *m_opaque_ap.get();
+}
+
+SBTypeSummaryOptions::SBTypeSummaryOptions (const lldb_private::TypeSummaryOptions *lldb_object_ptr)
+{
+ SetOptions(lldb_object_ptr);
+}
+
+void
+SBTypeSummaryOptions::SetOptions (const lldb_private::TypeSummaryOptions *lldb_object_ptr)
+{
+ if (lldb_object_ptr)
+ m_opaque_ap.reset(new TypeSummaryOptions(*lldb_object_ptr));
+ else
+ m_opaque_ap.reset(new TypeSummaryOptions());
+}
+
SBTypeSummary::SBTypeSummary() :
m_opaque_sp()
{
diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp
index 3a9621b1e3bc..0d3d7ad956ee 100644
--- a/source/API/SBValue.cpp
+++ b/source/API/SBValue.cpp
@@ -543,6 +543,36 @@ SBValue::GetObjectDescription ()
return cstr;
}
+const char *
+SBValue::GetTypeValidatorResult ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ const char *cstr = NULL;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ const auto& validation(value_sp->GetValidationStatus());
+ if (TypeValidatorResult::Failure == validation.first)
+ {
+ if (validation.second.empty())
+ cstr = "unknown error";
+ else
+ cstr = validation.second.c_str();
+ }
+ }
+ if (log)
+ {
+ if (cstr)
+ log->Printf ("SBValue(%p)::GetTypeValidatorResult() => \"%s\"",
+ static_cast<void*>(value_sp.get()), cstr);
+ else
+ log->Printf ("SBValue(%p)::GetTypeValidatorResult() => NULL",
+ static_cast<void*>(value_sp.get()));
+ }
+ return cstr;
+}
+
SBType
SBValue::GetType()
{
@@ -610,6 +640,32 @@ SBValue::GetSummary ()
}
return cstr;
}
+
+const char *
+SBValue::GetSummary (lldb::SBStream& stream,
+ lldb::SBTypeSummaryOptions& options)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ std::string buffer;
+ if (value_sp->GetSummaryAsCString(buffer,options.ref()) && !buffer.empty())
+ stream.Printf("%s",buffer.c_str());
+ }
+ const char* cstr = stream.GetData();
+ if (log)
+ {
+ if (cstr)
+ log->Printf ("SBValue(%p)::GetSummary() => \"%s\"",
+ static_cast<void*>(value_sp.get()), cstr);
+ else
+ log->Printf ("SBValue(%p)::GetSummary() => NULL",
+ static_cast<void*>(value_sp.get()));
+ }
+ return cstr;
+}
#endif // LLDB_DISABLE_PYTHON
const char *
@@ -808,21 +864,11 @@ SBValue::CreateValueFromExpression (const char *name, const char *expression, SB
if (value_sp)
{
ExecutionContext exe_ctx (value_sp->GetExecutionContextRef());
- Target* target = exe_ctx.GetTargetPtr();
- if (target)
- {
- options.ref().SetKeepInMemory(true);
- target->EvaluateExpression (expression,
- exe_ctx.GetFramePtr(),
- new_value_sp,
- options.ref());
- if (new_value_sp)
- {
- new_value_sp->SetName(ConstString(name));
- sb_value.SetSP(new_value_sp);
- }
- }
+ new_value_sp = ValueObject::CreateValueObjectFromExpression(name, expression, exe_ctx, options.ref());
+ if (new_value_sp)
+ new_value_sp->SetName(ConstString(name));
}
+ sb_value.SetSP(new_value_sp);
if (log)
{
if (new_value_sp)
@@ -846,30 +892,11 @@ SBValue::CreateValueFromAddress(const char* name, lldb::addr_t address, SBType s
lldb::TypeImplSP type_impl_sp (sb_type.GetSP());
if (value_sp && type_impl_sp)
{
- ClangASTType pointer_ast_type(type_impl_sp->GetClangASTType(false).GetPointerType ());
- if (pointer_ast_type)
- {
- lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&address,sizeof(lldb::addr_t)));
-
- ExecutionContext exe_ctx (value_sp->GetExecutionContextRef());
- ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
- pointer_ast_type,
- ConstString(name),
- buffer,
- exe_ctx.GetByteOrder(),
- exe_ctx.GetAddressByteSize()));
-
- if (ptr_result_valobj_sp)
- {
- ptr_result_valobj_sp->GetValue().SetValueType(Value::eValueTypeLoadAddress);
- Error err;
- new_value_sp = ptr_result_valobj_sp->Dereference(err);
- if (new_value_sp)
- new_value_sp->SetName(ConstString(name));
- }
- sb_value.SetSP(new_value_sp);
- }
+ ClangASTType ast_type(type_impl_sp->GetClangASTType(true));
+ ExecutionContext exe_ctx (value_sp->GetExecutionContextRef());
+ new_value_sp = ValueObject::CreateValueObjectFromAddress(name, address, exe_ctx, ast_type);
}
+ sb_value.SetSP(new_value_sp);
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
{
@@ -894,15 +921,10 @@ SBValue::CreateValueFromData (const char* name, SBData data, SBType type)
if (value_sp)
{
ExecutionContext exe_ctx (value_sp->GetExecutionContextRef());
-
- new_value_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
- type.m_opaque_sp->GetClangASTType(false),
- ConstString(name),
- *data.m_opaque_sp,
- LLDB_INVALID_ADDRESS);
+ new_value_sp = ValueObject::CreateValueObjectFromData(name, **data, exe_ctx, type.GetSP()->GetClangASTType(true));
new_value_sp->SetAddressTypeOfChildren(eAddressTypeLoad);
- sb_value.SetSP(new_value_sp);
}
+ sb_value.SetSP(new_value_sp);
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
{
@@ -1836,3 +1858,16 @@ SBValue::WatchPointee (bool resolve_location, bool read, bool write, SBError &er
sb_watchpoint = Dereference().Watch (resolve_location, read, write, error);
return sb_watchpoint;
}
+
+lldb::SBValue
+SBValue::Persist ()
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ SBValue persisted_sb;
+ if (value_sp)
+ {
+ persisted_sb.SetSP(value_sp->Persist());
+ }
+ return persisted_sb;
+}
diff --git a/source/API/SBValueList.cpp b/source/API/SBValueList.cpp
index 5069ed3f5624..71fabe0dfc0a 100644
--- a/source/API/SBValueList.cpp
+++ b/source/API/SBValueList.cpp
@@ -78,6 +78,21 @@ public:
}
return lldb::SBValue();
}
+
+ lldb::SBValue
+ GetFirstValueByName (const char* name) const
+ {
+ if (name)
+ {
+ for (auto val : m_values)
+ {
+ if (val.IsValid() && val.GetName() &&
+ strcmp(name,val.GetName()) == 0)
+ return val;
+ }
+ }
+ return lldb::SBValue();
+ }
private:
std::vector<lldb::SBValue> m_values;
@@ -261,6 +276,15 @@ SBValueList::FindValueObjectByUID (lldb::user_id_t uid)
return sb_value;
}
+SBValue
+SBValueList::GetFirstValueByName (const char* name) const
+{
+ SBValue sb_value;
+ if (m_opaque_ap.get())
+ sb_value = m_opaque_ap->GetFirstValueByName(name);
+ return sb_value;
+}
+
void *
SBValueList::opaque_ptr ()
{
diff --git a/source/Breakpoint/Breakpoint.cpp b/source/Breakpoint/Breakpoint.cpp
index 7d08170e4aed..bc269cdb95ac 100644
--- a/source/Breakpoint/Breakpoint.cpp
+++ b/source/Breakpoint/Breakpoint.cpp
@@ -20,11 +20,14 @@
#include "lldb/Breakpoint/BreakpointResolver.h"
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/SearchFilter.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
@@ -62,6 +65,20 @@ Breakpoint::Breakpoint(Target &target,
m_being_created = false;
}
+Breakpoint::Breakpoint (Target &new_target, Breakpoint &source_bp) :
+ m_being_created(true),
+ m_hardware(source_bp.m_hardware),
+ m_target(new_target),
+ m_name_list (source_bp.m_name_list),
+ m_options (source_bp.m_options),
+ m_locations(*this),
+ m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols)
+{
+ // Now go through and copy the filter & resolver:
+ m_resolver_sp = source_bp.m_resolver_sp->CopyForBreakpoint(*this);
+ m_filter_sp = source_bp.m_filter_sp->CopyForBreakpoint(*this);
+}
+
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
@@ -69,24 +86,16 @@ Breakpoint::~Breakpoint()
{
}
-bool
-Breakpoint::IsInternal () const
-{
- return LLDB_BREAK_ID_IS_INTERNAL(m_bid);
-}
-
-
-
-Target&
-Breakpoint::GetTarget ()
+const lldb::TargetSP
+Breakpoint::GetTargetSP ()
{
- return m_target;
+ return m_target.shared_from_this();
}
-const Target&
-Breakpoint::GetTarget () const
+bool
+Breakpoint::IsInternal () const
{
- return m_target;
+ return LLDB_BREAK_ID_IS_INTERNAL(m_bid);
}
BreakpointLocationSP
@@ -349,10 +358,41 @@ Breakpoint::ResolveBreakpoint ()
}
void
-Breakpoint::ResolveBreakpointInModules (ModuleList &module_list)
+Breakpoint::ResolveBreakpointInModules (ModuleList &module_list, BreakpointLocationCollection &new_locations)
+{
+ m_locations.StartRecordingNewLocations(new_locations);
+
+ m_resolver_sp->ResolveBreakpointInModules(*m_filter_sp, module_list);
+
+ m_locations.StopRecordingNewLocations();
+}
+
+void
+Breakpoint::ResolveBreakpointInModules (ModuleList &module_list, bool send_event)
{
if (m_resolver_sp)
- m_resolver_sp->ResolveBreakpointInModules(*m_filter_sp, module_list);
+ {
+ // If this is not an internal breakpoint, set up to record the new locations, then dispatch
+ // an event with the new locations.
+ if (!IsInternal() && send_event)
+ {
+ BreakpointEventData *new_locations_event = new BreakpointEventData (eBreakpointEventTypeLocationsAdded,
+ shared_from_this());
+
+ ResolveBreakpointInModules (module_list, new_locations_event->GetBreakpointLocationCollection());
+
+ if (new_locations_event->GetBreakpointLocationCollection().GetSize() != 0)
+ {
+ SendBreakpointChangedEvent (new_locations_event);
+ }
+ else
+ delete new_locations_event;
+ }
+ else
+ {
+ m_resolver_sp->ResolveBreakpointInModules(*m_filter_sp, module_list);
+ }
+ }
}
void
@@ -368,6 +408,11 @@ Breakpoint::ClearAllBreakpointSites ()
void
Breakpoint::ModulesChanged (ModuleList &module_list, bool load, bool delete_locations)
{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("Breakpoint::ModulesChanged: num_modules: %zu load: %i delete_locations: %i\n",
+ module_list.GetSize(), load, delete_locations);
+
Mutex::Locker modules_mutex(module_list.GetMutex());
if (load)
{
@@ -383,32 +428,27 @@ Breakpoint::ModulesChanged (ModuleList &module_list, bool load, bool delete_loca
// them after the locations pass. Have to do it this way because
// resolving breakpoints will add new locations potentially.
- const size_t num_locs = m_locations.GetSize();
- size_t num_modules = module_list.GetSize();
- for (size_t i = 0; i < num_modules; i++)
+ for (ModuleSP module_sp : module_list.ModulesNoLocking())
{
bool seen = false;
- ModuleSP module_sp (module_list.GetModuleAtIndexUnlocked (i));
if (!m_filter_sp->ModulePasses (module_sp))
continue;
- for (size_t loc_idx = 0; loc_idx < num_locs; loc_idx++)
+ for (BreakpointLocationSP break_loc_sp : m_locations.BreakpointLocations())
{
- BreakpointLocationSP break_loc = m_locations.GetByIndex(loc_idx);
- if (!break_loc->IsEnabled())
+ if (!break_loc_sp->IsEnabled())
continue;
- SectionSP section_sp (break_loc->GetAddress().GetSection());
+ SectionSP section_sp (break_loc_sp->GetAddress().GetSection());
if (!section_sp || section_sp->GetModule() == module_sp)
{
if (!seen)
seen = true;
- if (!break_loc->ResolveBreakpointSite())
+ if (!break_loc_sp->ResolveBreakpointSite())
{
- Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf ("Warning: could not set breakpoint site for breakpoint location %d of breakpoint %d.\n",
- break_loc->GetID(), GetID());
+ break_loc_sp->GetID(), GetID());
}
}
}
@@ -420,28 +460,7 @@ Breakpoint::ModulesChanged (ModuleList &module_list, bool load, bool delete_loca
if (new_modules.GetSize() > 0)
{
- // If this is not an internal breakpoint, set up to record the new locations, then dispatch
- // an event with the new locations.
- if (!IsInternal())
- {
- BreakpointEventData *new_locations_event = new BreakpointEventData (eBreakpointEventTypeLocationsAdded,
- shared_from_this());
-
- m_locations.StartRecordingNewLocations(new_locations_event->GetBreakpointLocationCollection());
-
- ResolveBreakpointInModules(new_modules);
-
- m_locations.StopRecordingNewLocations();
- if (new_locations_event->GetBreakpointLocationCollection().GetSize() != 0)
- {
- SendBreakpointChangedEvent (new_locations_event);
- }
- else
- delete new_locations_event;
- }
- else
- ResolveBreakpointInModules(new_modules);
-
+ ResolveBreakpointInModules(new_modules);
}
}
else
@@ -498,21 +517,251 @@ Breakpoint::ModulesChanged (ModuleList &module_list, bool load, bool delete_loca
}
}
+namespace
+{
+static bool
+SymbolContextsMightBeEquivalent(SymbolContext &old_sc, SymbolContext &new_sc)
+{
+ bool equivalent_scs = false;
+
+ if (old_sc.module_sp.get() == new_sc.module_sp.get())
+ {
+ // If these come from the same module, we can directly compare the pointers:
+ if (old_sc.comp_unit && new_sc.comp_unit
+ && (old_sc.comp_unit == new_sc.comp_unit))
+ {
+ if (old_sc.function && new_sc.function
+ && (old_sc.function == new_sc.function))
+ {
+ equivalent_scs = true;
+ }
+ }
+ else if (old_sc.symbol && new_sc.symbol
+ && (old_sc.symbol == new_sc.symbol))
+ {
+ equivalent_scs = true;
+ }
+ }
+ else
+ {
+ // Otherwise we will compare by name...
+ if (old_sc.comp_unit && new_sc.comp_unit)
+ {
+ if (FileSpec::Equal(*old_sc.comp_unit, *new_sc.comp_unit, true))
+ {
+ // Now check the functions:
+ if (old_sc.function && new_sc.function
+ && (old_sc.function->GetName() == new_sc.function->GetName()))
+ {
+ equivalent_scs = true;
+ }
+ }
+ }
+ else if (old_sc.symbol && new_sc.symbol)
+ {
+ if (Mangled::Compare(old_sc.symbol->GetMangled(), new_sc.symbol->GetMangled()) == 0)
+ {
+ equivalent_scs = true;
+ }
+ }
+ }
+ return equivalent_scs;
+}
+}
+
void
Breakpoint::ModuleReplaced (ModuleSP old_module_sp, ModuleSP new_module_sp)
{
- ModuleList temp_list;
- temp_list.Append (new_module_sp);
- ModulesChanged (temp_list, true);
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("Breakpoint::ModulesReplaced for %s\n",
+ old_module_sp->GetSpecificationDescription().c_str());
+ // First find all the locations that are in the old module
+
+ BreakpointLocationCollection old_break_locs;
+ for (BreakpointLocationSP break_loc_sp : m_locations.BreakpointLocations())
+ {
+ SectionSP section_sp = break_loc_sp->GetAddress().GetSection();
+ if (section_sp && section_sp->GetModule() == old_module_sp)
+ {
+ old_break_locs.Add(break_loc_sp);
+ }
+ }
+
+ size_t num_old_locations = old_break_locs.GetSize();
+
+ if (num_old_locations == 0)
+ {
+ // There were no locations in the old module, so we just need to check if there were any in the new module.
+ ModuleList temp_list;
+ temp_list.Append (new_module_sp);
+ ResolveBreakpointInModules(temp_list);
+ }
+ else
+ {
+ // First search the new module for locations.
+ // Then compare this with the old list, copy over locations that "look the same"
+ // Then delete the old locations.
+ // Finally remember to post the creation event.
+ //
+ // Two locations are the same if they have the same comp unit & function (by name) and there are the same number
+ // of locations in the old function as in the new one.
+
+ ModuleList temp_list;
+ temp_list.Append (new_module_sp);
+ BreakpointLocationCollection new_break_locs;
+ ResolveBreakpointInModules(temp_list, new_break_locs);
+ BreakpointLocationCollection locations_to_remove;
+ BreakpointLocationCollection locations_to_announce;
+
+ size_t num_new_locations = new_break_locs.GetSize();
+
+ if (num_new_locations > 0)
+ {
+ // Break out the case of one location -> one location since that's the most common one, and there's no need
+ // to build up the structures needed for the merge in that case.
+ if (num_new_locations == 1 && num_old_locations == 1)
+ {
+ bool equivalent_locations = false;
+ SymbolContext old_sc, new_sc;
+ // The only way the old and new location can be equivalent is if they have the same amount of information:
+ BreakpointLocationSP old_loc_sp = old_break_locs.GetByIndex(0);
+ BreakpointLocationSP new_loc_sp = new_break_locs.GetByIndex(0);
+
+ if (old_loc_sp->GetAddress().CalculateSymbolContext(&old_sc)
+ == new_loc_sp->GetAddress().CalculateSymbolContext(&new_sc))
+ {
+ equivalent_locations = SymbolContextsMightBeEquivalent(old_sc, new_sc);
+ }
+
+ if (equivalent_locations)
+ {
+ m_locations.SwapLocation (old_loc_sp, new_loc_sp);
+ }
+ else
+ {
+ locations_to_remove.Add(old_loc_sp);
+ locations_to_announce.Add(new_loc_sp);
+ }
+ }
+ else
+ {
+ //We don't want to have to keep computing the SymbolContexts for these addresses over and over,
+ // so lets get them up front:
+
+ typedef std::map<lldb::break_id_t, SymbolContext> IDToSCMap;
+ IDToSCMap old_sc_map;
+ for (size_t idx = 0; idx < num_old_locations; idx++)
+ {
+ SymbolContext sc;
+ BreakpointLocationSP bp_loc_sp = old_break_locs.GetByIndex(idx);
+ lldb::break_id_t loc_id = bp_loc_sp->GetID();
+ bp_loc_sp->GetAddress().CalculateSymbolContext(&old_sc_map[loc_id]);
+ }
+
+ std::map<lldb::break_id_t, SymbolContext> new_sc_map;
+ for (size_t idx = 0; idx < num_new_locations; idx++)
+ {
+ SymbolContext sc;
+ BreakpointLocationSP bp_loc_sp = new_break_locs.GetByIndex(idx);
+ lldb::break_id_t loc_id = bp_loc_sp->GetID();
+ bp_loc_sp->GetAddress().CalculateSymbolContext(&new_sc_map[loc_id]);
+ }
+ // Take an element from the old Symbol Contexts
+ while (old_sc_map.size() > 0)
+ {
+ lldb::break_id_t old_id = old_sc_map.begin()->first;
+ SymbolContext &old_sc = old_sc_map.begin()->second;
+
+ // Count the number of entries equivalent to this SC for the old list:
+ std::vector<lldb::break_id_t> old_id_vec;
+ old_id_vec.push_back(old_id);
+
+ IDToSCMap::iterator tmp_iter;
+ for (tmp_iter = ++old_sc_map.begin(); tmp_iter != old_sc_map.end(); tmp_iter++)
+ {
+ if (SymbolContextsMightBeEquivalent (old_sc, tmp_iter->second))
+ old_id_vec.push_back (tmp_iter->first);
+ }
+
+ // Now find all the equivalent locations in the new list.
+ std::vector<lldb::break_id_t> new_id_vec;
+ for (tmp_iter = new_sc_map.begin(); tmp_iter != new_sc_map.end(); tmp_iter++)
+ {
+ if (SymbolContextsMightBeEquivalent (old_sc, tmp_iter->second))
+ new_id_vec.push_back(tmp_iter->first);
+ }
+
+ // Alright, if we have the same number of potentially equivalent locations in the old
+ // and new modules, we'll just map them one to one in ascending ID order (assuming the
+ // resolver's order would match the equivalent ones.
+ // Otherwise, we'll dump all the old ones, and just take the new ones, erasing the elements
+ // from both maps as we go.
+
+ if (old_id_vec.size() == new_id_vec.size())
+ {
+ sort(old_id_vec.begin(), old_id_vec.end());
+ sort(new_id_vec.begin(), new_id_vec.end());
+ size_t num_elements = old_id_vec.size();
+ for (size_t idx = 0; idx < num_elements; idx++)
+ {
+ BreakpointLocationSP old_loc_sp = old_break_locs.FindByIDPair(GetID(), old_id_vec[idx]);
+ BreakpointLocationSP new_loc_sp = new_break_locs.FindByIDPair(GetID(), new_id_vec[idx]);
+ m_locations.SwapLocation(old_loc_sp, new_loc_sp);
+ old_sc_map.erase(old_id_vec[idx]);
+ new_sc_map.erase(new_id_vec[idx]);
+ }
+ }
+ else
+ {
+ for (lldb::break_id_t old_id : old_id_vec)
+ {
+ locations_to_remove.Add(old_break_locs.FindByIDPair(GetID(), old_id));
+ old_sc_map.erase(old_id);
+ }
+ for (lldb::break_id_t new_id : new_id_vec)
+ {
+ locations_to_announce.Add(new_break_locs.FindByIDPair(GetID(), new_id));
+ new_sc_map.erase(new_id);
+ }
+ }
+ }
+ }
+ }
+
+ // Now remove the remaining old locations, and cons up a removed locations event.
+ // Note, we don't put the new locations that were swapped with an old location on the locations_to_remove
+ // list, so we don't need to worry about telling the world about removing a location we didn't tell them
+ // about adding.
+
+ BreakpointEventData *locations_event;
+ if (!IsInternal())
+ locations_event = new BreakpointEventData (eBreakpointEventTypeLocationsRemoved,
+ shared_from_this());
+ else
+ locations_event = NULL;
- // TO DO: For now I'm just adding locations for the new module and removing the
- // breakpoint locations that were in the old module.
- // We should really go find the ones that are in the new module & if we can determine that they are "equivalent"
- // carry over the options from the old location to the new.
+ for (BreakpointLocationSP loc_sp : locations_to_remove.BreakpointLocations())
+ {
+ m_locations.RemoveLocation(loc_sp);
+ if (locations_event)
+ locations_event->GetBreakpointLocationCollection().Add(loc_sp);
+ }
+ SendBreakpointChangedEvent (locations_event);
+
+ // And announce the new ones.
+
+ if (!IsInternal())
+ {
+ locations_event = new BreakpointEventData (eBreakpointEventTypeLocationsAdded,
+ shared_from_this());
+ for (BreakpointLocationSP loc_sp : locations_to_announce.BreakpointLocations())
+ locations_event->GetBreakpointLocationCollection().Add(loc_sp);
- temp_list.Clear();
- temp_list.Append (old_module_sp);
- ModulesChanged (temp_list, false, true);
+ SendBreakpointChangedEvent (locations_event);
+ }
+ m_locations.Compact();
+ }
}
void
@@ -534,6 +783,23 @@ Breakpoint::GetNumLocations() const
return m_locations.GetSize();
}
+bool
+Breakpoint::AddName (const char *new_name, Error &error)
+{
+ if (!new_name)
+ return false;
+ if (!BreakpointID::StringIsBreakpointName(new_name, error))
+ {
+ error.SetErrorStringWithFormat("input name \"%s\" not a breakpoint name.", new_name);
+ return false;
+ }
+ if (!error.Success())
+ return false;
+
+ m_name_list.insert(new_name);
+ return true;
+}
+
void
Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_locations)
{
@@ -584,6 +850,20 @@ Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_l
if (level == lldb::eDescriptionLevelFull)
{
+ if (!m_name_list.empty())
+ {
+ s->EOL();
+ s->Indent();
+ s->Printf ("Names:");
+ s->EOL();
+ s->IndentMore();
+ for (std::string name : m_name_list)
+ {
+ s->Indent();
+ s->Printf("%s\n", name.c_str());
+ }
+ s->IndentLess();
+ }
s->IndentLess();
s->EOL();
}
diff --git a/source/Breakpoint/BreakpointID.cpp b/source/Breakpoint/BreakpointID.cpp
index 9963ed68303a..31823886dd9f 100644
--- a/source/Breakpoint/BreakpointID.cpp
+++ b/source/Breakpoint/BreakpointID.cpp
@@ -18,6 +18,7 @@
#include "lldb/Breakpoint/BreakpointID.h"
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Core/Stream.h"
+#include "lldb/Core/Error.h"
using namespace lldb;
using namespace lldb_private;
@@ -121,3 +122,19 @@ BreakpointID::ParseCanonicalReference (const char *input, break_id_t *break_id_p
return false;
}
+bool
+BreakpointID::StringIsBreakpointName(const char *name, Error &error)
+{
+ error.Clear();
+
+ if (name && (name[0] >= 'A' && name[0] <= 'z'))
+ {
+ if (strcspn(name, ".- ") != strlen(name))
+ {
+ error.SetErrorStringWithFormat("invalid breakpoint name: \"%s\"", name);
+ }
+ return true;
+ }
+ else
+ return false;
+}
diff --git a/source/Breakpoint/BreakpointIDList.cpp b/source/Breakpoint/BreakpointIDList.cpp
index 24101b1442fb..b8b506750b34 100644
--- a/source/Breakpoint/BreakpointIDList.cpp
+++ b/source/Breakpoint/BreakpointIDList.cpp
@@ -159,27 +159,52 @@ BreakpointIDList::InsertStringArray (const char **string_array, size_t array_siz
// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced by the members of the range.
void
-BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, CommandReturnObject &result,
+BreakpointIDList::FindAndReplaceIDRanges (Args &old_args,
+ Target *target,
+ bool allow_locations,
+ CommandReturnObject &result,
Args &new_args)
{
std::string range_start;
const char *range_end;
const char *current_arg;
const size_t num_old_args = old_args.GetArgumentCount();
+ std::set<std::string> names_found;
for (size_t i = 0; i < num_old_args; ++i)
{
bool is_range = false;
+
current_arg = old_args.GetArgumentAtIndex (i);
+ if (!allow_locations && strchr(current_arg, '.') != nullptr)
+ {
+ result.AppendErrorWithFormat ("Breakpoint locations not allowed, saw location: %s.", current_arg);
+ new_args.Clear();
+ return;
+ }
size_t range_start_len = 0;
size_t range_end_pos = 0;
+ Error error;
+
if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos))
{
is_range = true;
range_start.assign (current_arg, range_start_len);
range_end = current_arg + range_end_pos;
}
+ else if (BreakpointID::StringIsBreakpointName(current_arg, error))
+ {
+ if (!error.Success())
+ {
+ new_args.Clear();
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+ else
+ names_found.insert(current_arg);
+ }
else if ((i + 2 < num_old_args)
&& BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1))
&& BreakpointID::IsValidIDExpression (current_arg)
@@ -342,6 +367,23 @@ BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, Comman
}
}
+ // Okay, now see if we found any names, and if we did, add them:
+ if (target && names_found.size())
+ {
+ for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints())
+ {
+ for (std::string name : names_found)
+ {
+ if (bkpt_sp->MatchesName(name.c_str()))
+ {
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference (&canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
+ new_args.AppendArgument (canonical_id_str.GetData());
+ }
+ }
+ }
+ }
+
result.SetStatus (eReturnStatusSuccessFinishNoResult);
return;
}
diff --git a/source/Breakpoint/BreakpointLocation.cpp b/source/Breakpoint/BreakpointLocation.cpp
index e1ac043ae905..11ecfecc5bc7 100644
--- a/source/Breakpoint/BreakpointLocation.cpp
+++ b/source/Breakpoint/BreakpointLocation.cpp
@@ -449,8 +449,7 @@ BreakpointLocation::ShouldStop (StoppointCallbackContext *context)
bool should_stop = true;
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
- IncrementHitCount();
-
+ // Do this first, if a location is disabled, it shouldn't increment its hit count.
if (!IsEnabled())
return false;
@@ -474,6 +473,13 @@ BreakpointLocation::ShouldStop (StoppointCallbackContext *context)
return should_stop;
}
+void
+BreakpointLocation::BumpHitCount()
+{
+ if (IsEnabled())
+ IncrementHitCount();
+}
+
bool
BreakpointLocation::IsResolved () const
{
@@ -569,7 +575,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);
+ sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false, true);
}
else
{
@@ -717,4 +723,13 @@ BreakpointLocation::SendBreakpointLocationChangedEvent (lldb::BreakpointEventTyp
m_owner.GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged, data);
}
}
-
+
+void
+BreakpointLocation::SwapLocation (BreakpointLocationSP swap_from)
+{
+ m_address = swap_from->m_address;
+ m_should_resolve_indirect_functions = swap_from->m_should_resolve_indirect_functions;
+ m_is_reexported = swap_from->m_is_reexported;
+ m_is_indirect = swap_from->m_is_indirect;
+ m_user_expression_sp.reset();
+}
diff --git a/source/Breakpoint/BreakpointLocationCollection.cpp b/source/Breakpoint/BreakpointLocationCollection.cpp
index ee3f56f928d5..5756ccedfaa4 100644
--- a/source/Breakpoint/BreakpointLocationCollection.cpp
+++ b/source/Breakpoint/BreakpointLocationCollection.cpp
@@ -196,3 +196,4 @@ BreakpointLocationCollection::GetDescription (Stream *s, lldb::DescriptionLevel
(*pos)->GetDescription(s, level);
}
}
+
diff --git a/source/Breakpoint/BreakpointLocationList.cpp b/source/Breakpoint/BreakpointLocationList.cpp
index ae7f863ad090..06b270a08ce9 100644
--- a/source/Breakpoint/BreakpointLocationList.cpp
+++ b/source/Breakpoint/BreakpointLocationList.cpp
@@ -272,6 +272,20 @@ BreakpointLocationList::AddLocation (const Address &addr, bool resolve_indirect_
return bp_loc_sp;
}
+void
+BreakpointLocationList::SwapLocation (BreakpointLocationSP to_location_sp, BreakpointLocationSP from_location_sp)
+{
+ if (!from_location_sp || !to_location_sp)
+ return;
+
+ m_address_to_location.erase(to_location_sp->GetAddress());
+ to_location_sp->SwapLocation(from_location_sp);
+ RemoveLocation(from_location_sp);
+ m_address_to_location[to_location_sp->GetAddress()] = to_location_sp;
+ to_location_sp->ResolveBreakpointSite();
+}
+
+
bool
BreakpointLocationList::RemoveLocation (const lldb::BreakpointLocationSP &bp_loc_sp)
{
@@ -345,3 +359,16 @@ BreakpointLocationList::StopRecordingNewLocations ()
m_new_location_recorder = NULL;
}
+void
+BreakpointLocationList::Compact()
+{
+ lldb::break_id_t highest_id = 0;
+
+ for (BreakpointLocationSP loc_sp : m_locations)
+ {
+ lldb::break_id_t cur_id = loc_sp->GetID();
+ if (cur_id > highest_id)
+ highest_id = cur_id;
+ }
+ m_next_id = highest_id;
+}
diff --git a/source/Breakpoint/BreakpointOptions.cpp b/source/Breakpoint/BreakpointOptions.cpp
index ea8556d0930b..db76ffb8685c 100644
--- a/source/Breakpoint/BreakpointOptions.cpp
+++ b/source/Breakpoint/BreakpointOptions.cpp
@@ -237,8 +237,7 @@ BreakpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) cons
if (m_thread_spec_ap.get())
m_thread_spec_ap->GetDescription (s, level);
- else if (level == eDescriptionLevelBrief)
- s->PutCString ("thread spec: no ");
+
if (level == lldb::eDescriptionLevelFull)
{
s->IndentLess();
diff --git a/source/Breakpoint/BreakpointResolverAddress.cpp b/source/Breakpoint/BreakpointResolverAddress.cpp
index 1bcef93aedad..d6647130c54c 100644
--- a/source/Breakpoint/BreakpointResolverAddress.cpp
+++ b/source/Breakpoint/BreakpointResolverAddress.cpp
@@ -109,3 +109,11 @@ BreakpointResolverAddress::Dump (Stream *s) const
{
}
+
+lldb::BreakpointResolverSP
+BreakpointResolverAddress::CopyForBreakpoint (Breakpoint &breakpoint)
+{
+ lldb::BreakpointResolverSP ret_sp(new BreakpointResolverAddress(&breakpoint, m_addr));
+ return ret_sp;
+}
+
diff --git a/source/Breakpoint/BreakpointResolverFileLine.cpp b/source/Breakpoint/BreakpointResolverFileLine.cpp
index dcee2fd54125..950054c3d720 100644
--- a/source/Breakpoint/BreakpointResolverFileLine.cpp
+++ b/source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -110,3 +110,14 @@ BreakpointResolverFileLine::Dump (Stream *s) const
}
+lldb::BreakpointResolverSP
+BreakpointResolverFileLine::CopyForBreakpoint (Breakpoint &breakpoint)
+{
+ lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileLine(&breakpoint,
+ m_file_spec,
+ m_line_number,
+ m_inlines,
+ m_skip_prologue));
+
+ return ret_sp;
+}
diff --git a/source/Breakpoint/BreakpointResolverFileRegex.cpp b/source/Breakpoint/BreakpointResolverFileRegex.cpp
index 01aecee7b9c2..c71d9bf5ba8c 100644
--- a/source/Breakpoint/BreakpointResolverFileRegex.cpp
+++ b/source/Breakpoint/BreakpointResolverFileRegex.cpp
@@ -95,3 +95,10 @@ BreakpointResolverFileRegex::Dump (Stream *s) const
}
+lldb::BreakpointResolverSP
+BreakpointResolverFileRegex::CopyForBreakpoint (Breakpoint &breakpoint)
+{
+ lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(&breakpoint, m_regex));
+ return ret_sp;
+}
+
diff --git a/source/Breakpoint/BreakpointResolverName.cpp b/source/Breakpoint/BreakpointResolverName.cpp
index 3ac3ed06fc70..581f7b016173 100644
--- a/source/Breakpoint/BreakpointResolverName.cpp
+++ b/source/Breakpoint/BreakpointResolverName.cpp
@@ -121,6 +121,17 @@ BreakpointResolverName::~BreakpointResolverName ()
{
}
+BreakpointResolverName::BreakpointResolverName(const BreakpointResolverName &rhs) :
+ BreakpointResolver(rhs.m_breakpoint, BreakpointResolver::NameResolver),
+ m_lookups(rhs.m_lookups),
+ m_class_name(rhs.m_class_name),
+ m_regex(rhs.m_regex),
+ m_match_type (rhs.m_match_type),
+ m_skip_prologue (rhs.m_skip_prologue)
+{
+
+}
+
void
BreakpointResolverName::AddNameLookup (const ConstString &name, uint32_t name_type_mask)
{
@@ -371,3 +382,10 @@ BreakpointResolverName::Dump (Stream *s) const
}
+lldb::BreakpointResolverSP
+BreakpointResolverName::CopyForBreakpoint (Breakpoint &breakpoint)
+{
+ lldb::BreakpointResolverSP ret_sp(new BreakpointResolverName(*this));
+ ret_sp->SetBreakpoint(&breakpoint);
+ return ret_sp;
+}
diff --git a/source/Breakpoint/BreakpointSite.cpp b/source/Breakpoint/BreakpointSite.cpp
index 3cf6d37af379..469514b03f8a 100644
--- a/source/Breakpoint/BreakpointSite.cpp
+++ b/source/Breakpoint/BreakpointSite.cpp
@@ -199,6 +199,15 @@ BreakpointSite::ValidForThisThread (Thread *thread)
return m_owners.ValidForThisThread(thread);
}
+void
+BreakpointSite::BumpHitCounts()
+{
+ for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations())
+ {
+ loc_sp->BumpHitCount();
+ }
+}
+
bool
BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size, lldb::addr_t *intersect_addr, size_t *intersect_size, size_t *opcode_offset) const
{
diff --git a/source/Commands/CommandCompletions.cpp b/source/Commands/CommandCompletions.cpp
index f0ad4a896739..c65dd9d460f4 100644
--- a/source/Commands/CommandCompletions.cpp
+++ b/source/Commands/CommandCompletions.cpp
@@ -112,7 +112,7 @@ CommandCompletions::SourceFiles
if (searcher == NULL)
{
lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
- SearchFilter null_searcher (target_sp);
+ SearchFilterForUnconstrainedSearches null_searcher (target_sp);
completer.DoCompletion (&null_searcher);
}
else
@@ -375,7 +375,7 @@ CommandCompletions::Modules
if (searcher == NULL)
{
lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
- SearchFilter null_searcher (target_sp);
+ SearchFilterForUnconstrainedSearches null_searcher (target_sp);
completer.DoCompletion (&null_searcher);
}
else
@@ -406,7 +406,7 @@ CommandCompletions::Symbols
if (searcher == NULL)
{
lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
- SearchFilter null_searcher (target_sp);
+ SearchFilterForUnconstrainedSearches null_searcher (target_sp);
completer.DoCompletion (&null_searcher);
}
else
diff --git a/source/Commands/CommandObjectBreakpoint.cpp b/source/Commands/CommandObjectBreakpoint.cpp
index 13bf1278c78c..3d4b3aff6fff 100644
--- a/source/Commands/CommandObjectBreakpoint.cpp
+++ b/source/Commands/CommandObjectBreakpoint.cpp
@@ -20,6 +20,8 @@
#include "lldb/Breakpoint/BreakpointIDList.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Interpreter/Options.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"
@@ -145,6 +147,10 @@ public:
m_condition.assign(option_arg);
break;
+ case 'D':
+ m_use_dummy = true;
+ break;
+
case 'E':
{
LanguageType language = LanguageRuntime::GetLanguageTypeFromString (option_arg);
@@ -236,6 +242,11 @@ public:
m_func_name_type_mask |= eFunctionNameTypeAuto;
break;
+ case 'N':
+ if (BreakpointID::StringIsBreakpointName(option_arg, error))
+ m_breakpoint_names.push_back (option_arg);
+ break;
+
case 'o':
m_one_shot = true;
break;
@@ -324,6 +335,8 @@ public:
m_language = eLanguageTypeUnknown;
m_skip_prologue = eLazyBoolCalculate;
m_one_shot = false;
+ m_use_dummy = false;
+ m_breakpoint_names.clear();
}
const OptionDefinition*
@@ -343,6 +356,7 @@ public:
uint32_t m_line_num;
uint32_t m_column;
std::vector<std::string> m_func_names;
+ std::vector<std::string> m_breakpoint_names;
uint32_t m_func_name_type_mask;
std::string m_func_regexp;
std::string m_source_text_regexp;
@@ -359,16 +373,18 @@ public:
lldb::LanguageType m_language;
LazyBool m_skip_prologue;
bool m_one_shot;
+ bool m_use_dummy;
};
protected:
virtual bool
DoExecute (Args& command,
- CommandReturnObject &result)
+ CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
- if (target == NULL)
+ Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
+
+ if (target == nullptr)
{
result.AppendError ("Invalid target. Must set target before setting breakpoints (see 'target create' command).");
result.SetStatus (eReturnStatusFailed);
@@ -551,6 +567,13 @@ protected:
if (!m_options.m_condition.empty())
bp->GetOptions()->SetCondition(m_options.m_condition.c_str());
+
+ if (!m_options.m_breakpoint_names.empty())
+ {
+ Error error; // We don't need to check the error here, since the option parser checked it...
+ for (auto name : m_options.m_breakpoint_names)
+ bp->AddName(name.c_str(), error);
+ }
bp->SetOneShot (m_options.m_one_shot);
}
@@ -560,10 +583,17 @@ protected:
Stream &output_stream = result.GetOutputStream();
const bool show_locations = false;
bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, show_locations);
- // Don't print out this warning for exception breakpoints. They can get set before the target
- // is set, but we won't know how to actually set the breakpoint till we run.
- if (bp->GetNumLocations() == 0 && break_type != eSetTypeException)
- output_stream.Printf ("WARNING: Unable to resolve breakpoint to any actual locations.\n");
+ if (target == m_interpreter.GetDebugger().GetDummyTarget())
+ output_stream.Printf ("Breakpoint set in dummy target, will get copied into future targets.\n");
+ else
+ {
+ // Don't print out this warning for exception breakpoints. They can get set before the target
+ // is set, but we won't know how to actually set the breakpoint till we run.
+ if (bp->GetNumLocations() == 0 && break_type != eSetTypeException)
+ {
+ output_stream.Printf ("WARNING: Unable to resolve breakpoint to any actual locations.\n");
+ }
+ }
result.SetStatus (eReturnStatusSuccessFinishResult);
}
else if (!bp)
@@ -709,6 +739,12 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
{ 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." },
+ { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
+ "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
+
+ { LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointName,
+ "Adds this to the list of names for this breakopint."},
+
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -766,7 +802,8 @@ public:
m_name_passed (false),
m_queue_passed (false),
m_condition_passed (false),
- m_one_shot_passed (false)
+ m_one_shot_passed (false),
+ m_use_dummy (false)
{
}
@@ -792,6 +829,9 @@ public:
m_enable_passed = true;
m_enable_value = false;
break;
+ case 'D':
+ m_use_dummy = true;
+ break;
case 'e':
m_enable_passed = true;
m_enable_value = true;
@@ -888,6 +928,7 @@ public:
m_name_passed = false;
m_condition_passed = false;
m_one_shot_passed = false;
+ m_use_dummy = false;
}
const OptionDefinition*
@@ -918,6 +959,7 @@ public:
bool m_queue_passed;
bool m_condition_passed;
bool m_one_shot_passed;
+ bool m_use_dummy;
};
@@ -925,7 +967,7 @@ protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
if (target == NULL)
{
result.AppendError ("Invalid target. No existing target or breakpoints.");
@@ -938,7 +980,7 @@ protected:
BreakpointIDList valid_bp_ids;
- CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
if (result.Succeeded())
{
@@ -1024,6 +1066,8 @@ CommandObjectBreakpointModify::CommandOptions::g_option_table[] =
{ LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true."},
{ LLDB_OPT_SET_1, false, "enable", 'e', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Enable the breakpoint."},
{ LLDB_OPT_SET_2, false, "disable", 'd', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Disable the breakpoint."},
+{ LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
+
{ 0, false, NULL, 0 , 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1055,7 +1099,7 @@ protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget();
if (target == NULL)
{
result.AppendError ("Invalid target. No existing target or breakpoints.");
@@ -1088,7 +1132,7 @@ protected:
{
// Particular breakpoint selected; enable that breakpoint.
BreakpointIDList valid_bp_ids;
- CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
if (result.Succeeded())
{
@@ -1175,7 +1219,7 @@ protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget();
if (target == NULL)
{
result.AppendError ("Invalid target. No existing target or breakpoints.");
@@ -1208,7 +1252,7 @@ protected:
// Particular breakpoint selected; disable that breakpoint.
BreakpointIDList valid_bp_ids;
- CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
if (result.Succeeded())
{
@@ -1293,7 +1337,8 @@ public:
CommandOptions (CommandInterpreter &interpreter) :
Options (interpreter),
- m_level (lldb::eDescriptionLevelBrief) // Breakpoint List defaults to brief descriptions
+ m_level (lldb::eDescriptionLevelBrief),
+ m_use_dummy(false)
{
}
@@ -1311,6 +1356,9 @@ public:
case 'b':
m_level = lldb::eDescriptionLevelBrief;
break;
+ case 'D':
+ m_use_dummy = true;
+ break;
case 'f':
m_level = lldb::eDescriptionLevelFull;
break;
@@ -1333,6 +1381,7 @@ public:
{
m_level = lldb::eDescriptionLevelFull;
m_internal = false;
+ m_use_dummy = false;
}
const OptionDefinition *
@@ -1350,13 +1399,15 @@ public:
lldb::DescriptionLevel m_level;
bool m_internal;
+ bool m_use_dummy;
};
protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
+
if (target == NULL)
{
result.AppendError ("Invalid target. No current target or breakpoints.");
@@ -1394,7 +1445,7 @@ protected:
{
// Particular breakpoints selected; show info about that breakpoint.
BreakpointIDList valid_bp_ids;
- CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
if (result.Succeeded())
{
@@ -1438,6 +1489,9 @@ CommandObjectBreakpointList::CommandOptions::g_option_table[] =
{ LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
"Explain everything we know about the breakpoint (for debugging debugger bugs)." },
+ { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
+ "List Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
+
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1540,7 +1594,7 @@ protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget();
if (target == NULL)
{
result.AppendError ("Invalid target. No existing target or breakpoints.");
@@ -1656,7 +1710,8 @@ public:
CommandObjectParsed (interpreter,
"breakpoint delete",
"Delete the specified breakpoint(s). If no breakpoints are specified, delete them all.",
- NULL)
+ NULL),
+ m_options (interpreter)
{
CommandArgumentEntry arg;
CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange);
@@ -1667,11 +1722,78 @@ public:
virtual
~CommandObjectBreakpointDelete () {}
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_use_dummy (false),
+ m_force (false)
+ {
+ }
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'f':
+ m_force = true;
+ break;
+
+ case 'D':
+ m_use_dummy = true;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_use_dummy = false;
+ m_force = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ bool m_use_dummy;
+ bool m_force;
+ };
+
protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
+
if (target == NULL)
{
result.AppendError ("Invalid target. No existing target or breakpoints.");
@@ -1695,7 +1817,7 @@ protected:
if (command.GetArgumentCount() == 0)
{
- if (!m_interpreter.Confirm ("About to delete all breakpoints, do you want to do that?", true))
+ if (!m_options.m_force && !m_interpreter.Confirm ("About to delete all breakpoints, do you want to do that?", true))
{
result.AppendMessage("Operation cancelled...");
}
@@ -1710,7 +1832,7 @@ protected:
{
// Particular breakpoint selected; disable that breakpoint.
BreakpointIDList valid_bp_ids;
- CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
if (result.Succeeded())
{
@@ -1748,7 +1870,416 @@ protected:
}
return result.Succeeded();
}
+private:
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectBreakpointDelete::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "force", 'f', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
+ "Delete all breakpoints without querying for confirmation."},
+
+ { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
+ "Delete Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
+
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointName
+//-------------------------------------------------------------------------
+
+static OptionDefinition
+g_breakpoint_name_options[] =
+{
+ { LLDB_OPT_SET_1, false, "name", 'N', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."},
+ { LLDB_OPT_SET_2, false, "breakpoint-id", 'B', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointID, "Specify a breakpoint id to use."},
+ { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
+ "Operate on Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
};
+class BreakpointNameOptionGroup : public OptionGroup
+{
+public:
+ BreakpointNameOptionGroup() :
+ OptionGroup(),
+ m_breakpoint(LLDB_INVALID_BREAK_ID),
+ m_use_dummy (false)
+ {
+
+ }
+
+ virtual
+ ~BreakpointNameOptionGroup ()
+ {
+ }
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return sizeof (g_breakpoint_name_options) / sizeof (OptionDefinition);
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_breakpoint_name_options;
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value)
+ {
+ Error error;
+ const int short_option = g_breakpoint_name_options[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'N':
+ if (BreakpointID::StringIsBreakpointName(option_value, error) && error.Success())
+ m_name.SetValueFromCString(option_value);
+ break;
+
+ case 'B':
+ if (m_breakpoint.SetValueFromCString(option_value).Fail())
+ error.SetErrorStringWithFormat ("unrecognized value \"%s\" for breakpoint", option_value);
+ break;
+ case 'D':
+ if (m_use_dummy.SetValueFromCString(option_value).Fail())
+ error.SetErrorStringWithFormat ("unrecognized value \"%s\" for use-dummy", option_value);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter)
+ {
+ m_name.Clear();
+ m_breakpoint.Clear();
+ m_use_dummy.Clear();
+ m_use_dummy.SetDefaultValue(false);
+ }
+
+ OptionValueString m_name;
+ OptionValueUInt64 m_breakpoint;
+ OptionValueBoolean m_use_dummy;
+};
+
+
+class CommandObjectBreakpointNameAdd : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointNameAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "add",
+ "Add a name to the breakpoints provided.",
+ "breakpoint name add <command-options> <breakpoint-id-list>"),
+ m_name_options(),
+ m_option_group(interpreter)
+ {
+ // Create the first variant for the first (and only) argument for this command.
+ CommandArgumentEntry arg1;
+ CommandArgumentData id_arg;
+ id_arg.arg_type = eArgTypeBreakpointID;
+ id_arg.arg_repetition = eArgRepeatOptional;
+ arg1.push_back(id_arg);
+ m_arguments.push_back (arg1);
+
+ m_option_group.Append (&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectBreakpointNameAdd () {}
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ if (!m_name_options.m_name.OptionWasSet())
+ {
+ result.SetError("No name option provided.");
+ return false;
+ }
+
+ Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
+
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Mutex::Locker locker;
+ target->GetBreakpointList().GetListMutex(locker);
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+
+ size_t num_breakpoints = breakpoints.GetSize();
+ if (num_breakpoints == 0)
+ {
+ result.SetError("No breakpoints, cannot add names.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Particular breakpoint selected; disable that breakpoint.
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ if (valid_bp_ids.GetSize() == 0)
+ {
+ result.SetError("No breakpoints specified, cannot add names.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ size_t num_valid_ids = valid_bp_ids.GetSize();
+ for (size_t index = 0; index < num_valid_ids; index++)
+ {
+ lldb::break_id_t bp_id = valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
+ BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
+ Error error; // We don't need to check the error here, since the option parser checked it...
+ bp_sp->AddName(m_name_options.m_name.GetCurrentValue(), error);
+ }
+ }
+
+ return true;
+ }
+
+private:
+ BreakpointNameOptionGroup m_name_options;
+ OptionGroupOptions m_option_group;
+};
+
+
+
+class CommandObjectBreakpointNameDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointNameDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "delete",
+ "Delete a name from the breakpoints provided.",
+ "breakpoint name delete <command-options> <breakpoint-id-list>"),
+ m_name_options(),
+ m_option_group(interpreter)
+ {
+ // Create the first variant for the first (and only) argument for this command.
+ CommandArgumentEntry arg1;
+ CommandArgumentData id_arg;
+ id_arg.arg_type = eArgTypeBreakpointID;
+ id_arg.arg_repetition = eArgRepeatOptional;
+ arg1.push_back(id_arg);
+ m_arguments.push_back (arg1);
+
+ m_option_group.Append (&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectBreakpointNameDelete () {}
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ if (!m_name_options.m_name.OptionWasSet())
+ {
+ result.SetError("No name option provided.");
+ return false;
+ }
+
+ Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
+
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Mutex::Locker locker;
+ target->GetBreakpointList().GetListMutex(locker);
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+
+ size_t num_breakpoints = breakpoints.GetSize();
+ if (num_breakpoints == 0)
+ {
+ result.SetError("No breakpoints, cannot delete names.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Particular breakpoint selected; disable that breakpoint.
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ if (valid_bp_ids.GetSize() == 0)
+ {
+ result.SetError("No breakpoints specified, cannot delete names.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ size_t num_valid_ids = valid_bp_ids.GetSize();
+ for (size_t index = 0; index < num_valid_ids; index++)
+ {
+ lldb::break_id_t bp_id = valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
+ BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
+ bp_sp->RemoveName(m_name_options.m_name.GetCurrentValue());
+ }
+ }
+
+ return true;
+ }
+
+private:
+ BreakpointNameOptionGroup m_name_options;
+ OptionGroupOptions m_option_group;
+};
+
+class CommandObjectBreakpointNameList : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointNameList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "list",
+ "List either the names for a breakpoint or the breakpoints for a given name.",
+ "breakpoint name list <command-options>"),
+ m_name_options(),
+ m_option_group(interpreter)
+ {
+ m_option_group.Append (&m_name_options);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectBreakpointNameList () {}
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
+
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_name_options.m_name.OptionWasSet())
+ {
+ const char *name = m_name_options.m_name.GetCurrentValue();
+ Mutex::Locker locker;
+ target->GetBreakpointList().GetListMutex(locker);
+
+ BreakpointList &breakpoints = target->GetBreakpointList();
+ for (BreakpointSP bp_sp : breakpoints.Breakpoints())
+ {
+ if (bp_sp->MatchesName(name))
+ {
+ StreamString s;
+ bp_sp->GetDescription(&s, eDescriptionLevelBrief);
+ s.EOL();
+ result.AppendMessage(s.GetData());
+ }
+ }
+
+ }
+ else if (m_name_options.m_breakpoint.OptionWasSet())
+ {
+ BreakpointSP bp_sp = target->GetBreakpointList().FindBreakpointByID(m_name_options.m_breakpoint.GetCurrentValue());
+ if (bp_sp)
+ {
+ std::vector<std::string> names;
+ bp_sp->GetNames (names);
+ result.AppendMessage ("Names:");
+ for (auto name : names)
+ result.AppendMessageWithFormat (" %s\n", name.c_str());
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Could not find breakpoint %" PRId64 ".\n",
+ m_name_options.m_breakpoint.GetCurrentValue());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.SetError ("Must specify -N or -B option to list.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ return true;
+ }
+
+private:
+ BreakpointNameOptionGroup m_name_options;
+ OptionGroupOptions m_option_group;
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordBreakpoint
+//-------------------------------------------------------------------------
+class CommandObjectBreakpointName : public CommandObjectMultiword
+{
+public:
+ CommandObjectBreakpointName (CommandInterpreter &interpreter) :
+ CommandObjectMultiword(interpreter,
+ "name",
+ "A set of commands to manage name tags for breakpoints",
+ "breakpoint name <command> [<command-options>]")
+ {
+ CommandObjectSP add_command_object (new CommandObjectBreakpointNameAdd (interpreter));
+ CommandObjectSP delete_command_object (new CommandObjectBreakpointNameDelete (interpreter));
+ CommandObjectSP list_command_object (new CommandObjectBreakpointNameList (interpreter));
+
+ LoadSubCommand ("add", add_command_object);
+ LoadSubCommand ("delete", delete_command_object);
+ LoadSubCommand ("list", list_command_object);
+
+ }
+
+ virtual
+ ~CommandObjectBreakpointName ()
+ {
+ }
+
+};
+
//-------------------------------------------------------------------------
// CommandObjectMultiwordBreakpoint
@@ -1769,6 +2300,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter
CommandObjectSP set_command_object (new CommandObjectBreakpointSet (interpreter));
CommandObjectSP command_command_object (new CommandObjectBreakpointCommand (interpreter));
CommandObjectSP modify_command_object (new CommandObjectBreakpointModify(interpreter));
+ CommandObjectSP name_command_object (new CommandObjectBreakpointName(interpreter));
list_command_object->SetCommandName ("breakpoint list");
enable_command_object->SetCommandName("breakpoint enable");
@@ -1778,6 +2310,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter
set_command_object->SetCommandName("breakpoint set");
command_command_object->SetCommandName ("breakpoint command");
modify_command_object->SetCommandName ("breakpoint modify");
+ name_command_object->SetCommandName ("breakpoint name");
LoadSubCommand ("list", list_command_object);
LoadSubCommand ("enable", enable_command_object);
@@ -1787,6 +2320,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter
LoadSubCommand ("set", set_command_object);
LoadSubCommand ("command", command_command_object);
LoadSubCommand ("modify", modify_command_object);
+ LoadSubCommand ("name", name_command_object);
}
CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint ()
@@ -1794,13 +2328,17 @@ CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint ()
}
void
-CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result,
- BreakpointIDList *valid_ids)
+CommandObjectMultiwordBreakpoint::VerifyIDs (Args &args,
+ Target *target,
+ bool allow_locations,
+ CommandReturnObject &result,
+ BreakpointIDList *valid_ids)
{
// args can be strings representing 1). integers (for breakpoint ids)
// 2). the full breakpoint & location canonical representation
// 3). the word "to" or a hyphen, representing a range (in which case there
// had *better* be an entry both before & after of one of the first two types.
+ // 4). A breakpoint name
// If args is empty, we will use the last created breakpoint (if there is one.)
Args temp_args;
@@ -1824,7 +2362,7 @@ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *targe
// the new TEMP_ARGS. Do not copy breakpoint id range strings over; instead generate a list of strings for
// all the breakpoint ids in the range, and shove all of those breakpoint id strings into TEMP_ARGS.
- BreakpointIDList::FindAndReplaceIDRanges (args, target, result, temp_args);
+ BreakpointIDList::FindAndReplaceIDRanges (args, target, allow_locations, result, temp_args);
// NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual BreakpointIDList:
diff --git a/source/Commands/CommandObjectBreakpoint.h b/source/Commands/CommandObjectBreakpoint.h
index 2d674b22d704..3fdd2a5f56be 100644
--- a/source/Commands/CommandObjectBreakpoint.h
+++ b/source/Commands/CommandObjectBreakpoint.h
@@ -38,8 +38,20 @@ public:
~CommandObjectMultiwordBreakpoint ();
static void
- VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids);
+ VerifyBreakpointOrLocationIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids)
+ {
+ VerifyIDs (args, target, true, result, valid_ids);
+ }
+ static void
+ VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids)
+ {
+ VerifyIDs (args, target, false, result, valid_ids);
+ }
+
+private:
+ static void
+ VerifyIDs (Args &args, Target *target, bool allow_locations, CommandReturnObject &result, BreakpointIDList *valid_ids);
};
} // namespace lldb_private
diff --git a/source/Commands/CommandObjectBreakpointCommand.cpp b/source/Commands/CommandObjectBreakpointCommand.cpp
index fdb87d11900b..8f8404b712a5 100644
--- a/source/Commands/CommandObjectBreakpointCommand.cpp
+++ b/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -307,17 +307,16 @@ one command per line.\n" );
result.SetImmediateOutputStream (output_stream);
result.SetImmediateErrorStream (error_stream);
- bool stop_on_continue = true;
- bool echo_commands = false;
- bool print_results = true;
-
- debugger.GetCommandInterpreter().HandleCommands (commands,
+ CommandInterpreterRunOptions options;
+ options.SetStopOnContinue(true);
+ options.SetStopOnError (data->stop_on_error);
+ options.SetEchoCommands (true);
+ options.SetPrintResults (true);
+ options.SetAddToHistory (false);
+
+ debugger.GetCommandInterpreter().HandleCommands (commands,
&exe_ctx,
- stop_on_continue,
- data->stop_on_error,
- echo_commands,
- print_results,
- eLazyBoolNo,
+ options,
result);
result.GetImmediateOutputStream()->Flush();
result.GetImmediateErrorStream()->Flush();
@@ -390,6 +389,10 @@ one command per line.\n" );
}
break;
+ case 'D':
+ m_use_dummy = true;
+ break;
+
default:
break;
}
@@ -406,6 +409,7 @@ one command per line.\n" );
m_stop_on_error = true;
m_one_liner.clear();
m_function_name.clear();
+ m_use_dummy = false;
}
const OptionDefinition*
@@ -429,13 +433,14 @@ one command per line.\n" );
std::string m_one_liner;
bool m_stop_on_error;
std::string m_function_name;
+ bool m_use_dummy;
};
protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
if (target == NULL)
{
@@ -462,7 +467,7 @@ protected:
}
BreakpointIDList valid_bp_ids;
- CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
m_bp_options_vec.clear();
@@ -581,6 +586,9 @@ CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] =
{ LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction,
"Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."},
+ { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
+ "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
+
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -595,7 +603,8 @@ public:
CommandObjectParsed (interpreter,
"delete",
"Delete the set of commands from a breakpoint.",
- NULL)
+ NULL),
+ m_options (interpreter)
{
CommandArgumentEntry arg;
CommandArgumentData bp_id_arg;
@@ -615,11 +624,70 @@ public:
virtual
~CommandObjectBreakpointCommandDelete () {}
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_use_dummy (false)
+ {
+ }
+
+ virtual
+ ~CommandOptions () {}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'D':
+ m_use_dummy = true;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_use_dummy = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ bool m_use_dummy;
+ };
+
protected:
virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
if (target == NULL)
{
@@ -646,7 +714,7 @@ protected:
}
BreakpointIDList valid_bp_ids;
- CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
if (result.Succeeded())
{
@@ -680,8 +748,20 @@ protected:
}
return result.Succeeded();
}
+private:
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectBreakpointCommandDelete::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
+ "Delete commands from Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
+
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
+
//-------------------------------------------------------------------------
// CommandObjectBreakpointCommandList
//-------------------------------------------------------------------------
@@ -744,7 +824,7 @@ protected:
}
BreakpointIDList valid_bp_ids;
- CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
if (result.Succeeded())
{
diff --git a/source/Commands/CommandObjectCommands.cpp b/source/Commands/CommandObjectCommands.cpp
index 7d9bb7dad8fd..f98eac055f24 100644
--- a/source/Commands/CommandObjectCommands.cpp
+++ b/source/Commands/CommandObjectCommands.cpp
@@ -366,7 +366,7 @@ protected:
// Instance variables to hold the values for command options.
OptionValueBoolean m_stop_on_error;
- OptionValueBoolean m_silent_run;
+ OptionValueBoolean m_silent_run;
OptionValueBoolean m_stop_on_continue;
};
@@ -387,14 +387,15 @@ protected:
m_options.m_stop_on_continue.OptionWasSet())
{
// Use user set settings
- LazyBool print_command = m_options.m_silent_run.GetCurrentValue() ? eLazyBoolNo : eLazyBoolYes;
+ CommandInterpreterRunOptions options;
+ options.SetStopOnContinue(m_options.m_stop_on_continue.GetCurrentValue());
+ options.SetStopOnError (m_options.m_stop_on_error.GetCurrentValue());
+ options.SetEchoCommands (!m_options.m_silent_run.GetCurrentValue());
+ options.SetPrintResults (!m_options.m_silent_run.GetCurrentValue());
+
m_interpreter.HandleCommandsFromFile (cmd_file,
exe_ctx,
- m_options.m_stop_on_continue.GetCurrentValue() ? eLazyBoolYes : eLazyBoolNo, // Stop on continue
- m_options.m_stop_on_error.GetCurrentValue() ? eLazyBoolYes : eLazyBoolNo, // Stop on error
- print_command, // Echo command
- print_command, // Print command output
- eLazyBoolCalculate, // Add to history
+ options,
result);
}
@@ -402,13 +403,10 @@ protected:
{
// No options were set, inherit any settings from nested "command source" commands,
// or set to sane default settings...
+ CommandInterpreterRunOptions options;
m_interpreter.HandleCommandsFromFile (cmd_file,
exe_ctx,
- eLazyBoolCalculate, // Stop on continue
- eLazyBoolCalculate, // Stop on error
- eLazyBoolCalculate, // Echo command
- eLazyBoolCalculate, // Print command output
- eLazyBoolCalculate, // Add to history
+ options,
result);
}
@@ -830,8 +828,16 @@ protected:
{
if (m_interpreter.CommandExists (command_name))
{
- result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
- command_name);
+ if (cmd_obj->IsRemovable())
+ {
+ result.AppendErrorWithFormat ("'%s' is not an alias, it is a debugger command which can be removed using the 'command delete' command.\n",
+ command_name);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
+ command_name);
+ }
result.SetStatus (eReturnStatusFailed);
}
else
@@ -868,6 +874,77 @@ protected:
}
};
+#pragma mark CommandObjectCommandsDelete
+//-------------------------------------------------------------------------
+// CommandObjectCommandsDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command delete",
+ "Allow the user to delete user-defined regular expression, python or multi-word commands.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData alias_arg;
+
+ // Define the first (and only) variant of this arg.
+ alias_arg.arg_type = eArgTypeCommandName;
+ alias_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (alias_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectCommandsDelete()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ CommandObject::CommandMap::iterator pos;
+
+ if (args.GetArgumentCount() != 0)
+ {
+ const char *command_name = args.GetArgumentAtIndex(0);
+ if (m_interpreter.CommandExists (command_name))
+ {
+ if (m_interpreter.RemoveCommand (command_name))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
+ command_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n",
+ command_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("must call '%s' with one or more valid user defined regular expression, python or multi-word command names", GetCommandName ());
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+};
+
//-------------------------------------------------------------------------
// CommandObjectCommandsAddRegex
//-------------------------------------------------------------------------
@@ -875,7 +952,7 @@ protected:
class CommandObjectCommandsAddRegex :
public CommandObjectParsed,
- public IOHandlerDelegate
+ public IOHandlerDelegateMultiline
{
public:
CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) :
@@ -883,7 +960,7 @@ public:
"command regex",
"Allow the user to create a regular expression command.",
"command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
- IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand),
+ IOHandlerDelegateMultiline ("", IOHandlerDelegate::Completion::LLDBCommand),
m_options (interpreter)
{
SetHelpLong(
@@ -920,8 +997,8 @@ public:
protected:
- virtual void
- IOHandlerActivated (IOHandler &io_handler)
+ void
+ IOHandlerActivated (IOHandler &io_handler) override
{
StreamFileSP output_sp(io_handler.GetOutputStreamFile());
if (output_sp)
@@ -931,8 +1008,8 @@ protected:
}
}
- virtual void
- IOHandlerInputComplete (IOHandler &io_handler, std::string &data)
+ void
+ IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override
{
io_handler.SetIsDone(true);
if (m_regex_cmd_ap.get())
@@ -944,7 +1021,6 @@ protected:
bool check_only = false;
for (size_t i=0; i<num_lines; ++i)
{
- printf ("regex[%zu] = %s\n", i, lines[i].c_str());
llvm::StringRef bytes_strref (lines[i]);
Error error = AppendRegexSubstitution (bytes_strref, check_only);
if (error.Fail())
@@ -964,54 +1040,9 @@ protected:
}
}
}
-
- virtual LineStatus
- IOHandlerLinesUpdated (IOHandler &io_handler,
- StringList &lines,
- uint32_t line_idx,
- Error &error)
- {
- if (line_idx == UINT32_MAX)
- {
- // Return true to indicate we are done getting lines (this
- // is a "fake" line - the real terminating blank line was
- // removed during a previous call with the code below)
- error.Clear();
- return LineStatus::Done;
- }
- else
- {
- const size_t num_lines = lines.GetSize();
- if (line_idx + 1 == num_lines)
- {
- // The last line was edited, if this line is empty, then we are done
- // getting our multiple lines.
- if (lines[line_idx].empty())
- {
- // Remove the last empty line from "lines" so it doesn't appear
- // in our final expression and return true to indicate we are done
- // getting lines
- lines.PopBack();
- return LineStatus::Done;
- }
- }
- // Check the current line to make sure it is formatted correctly
- bool check_only = true;
- llvm::StringRef regex_sed(lines[line_idx]);
- error = AppendRegexSubstitution (regex_sed, check_only);
- if (error.Fail())
- {
- return LineStatus::Error;
- }
- else
- {
- return LineStatus::Success;
- }
- }
- }
bool
- DoExecute (Args& command, CommandReturnObject &result)
+ DoExecute (Args& command, CommandReturnObject &result) override
{
const size_t argc = command.GetArgumentCount();
if (argc == 0)
@@ -1027,16 +1058,22 @@ protected:
name,
m_options.GetHelp (),
m_options.GetSyntax (),
- 10));
+ 10,
+ 0,
+ true));
if (argc == 1)
{
Debugger &debugger = m_interpreter.GetDebugger();
+ bool color_prompt = debugger.GetUseColor();
const bool multiple_lines = true; // Get multiple lines
IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
+ IOHandler::Type::Other,
"lldb-regex", // Name of input reader for history
- "\033[K> ", // Prompt and clear line
+ "> ", // Prompt
+ NULL, // Continuation prompt
multiple_lines,
+ color_prompt,
0, // Don't show line numbers
*this));
@@ -1110,21 +1147,25 @@ protected:
if (second_separator_char_pos == std::string::npos)
{
- error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s'",
+ error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s' in '%.*s'",
separator_char,
(int)(regex_sed.size() - first_separator_char_pos - 1),
- regex_sed.data() + (first_separator_char_pos + 1));
- return error;
+ regex_sed.data() + (first_separator_char_pos + 1),
+ (int)regex_sed.size(),
+ regex_sed.data());
+ return error;
}
const size_t third_separator_char_pos = regex_sed.find (separator_char, second_separator_char_pos + 1);
if (third_separator_char_pos == std::string::npos)
{
- error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s'",
+ error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s' in '%.*s'",
separator_char,
(int)(regex_sed.size() - second_separator_char_pos - 1),
- regex_sed.data() + (second_separator_char_pos + 1));
+ regex_sed.data() + (second_separator_char_pos + 1),
+ (int)regex_sed.size(),
+ regex_sed.data());
return error;
}
@@ -1262,8 +1303,8 @@ private:
std::string m_syntax;
};
- virtual Options *
- GetOptions ()
+ Options *
+ GetOptions () override
{
return &m_options;
}
@@ -1292,15 +1333,24 @@ public:
CommandObjectPythonFunction (CommandInterpreter &interpreter,
std::string name,
std::string funct,
+ std::string help,
ScriptedCommandSynchronicity synch) :
CommandObjectRaw (interpreter,
name.c_str(),
- (std::string("Run Python function ") + funct).c_str(),
+ NULL,
NULL),
m_function_name(funct),
m_synchro(synch),
m_fetched_help_long(false)
{
+ if (!help.empty())
+ SetHelp(help.c_str());
+ else
+ {
+ StreamString stream;
+ stream.Printf("For more information run 'help %s'",name.c_str());
+ SetHelp(stream.GetData());
+ }
}
virtual
@@ -1357,7 +1407,8 @@ protected:
raw_command_line,
m_synchro,
result,
- error) == false)
+ error,
+ m_exe_ctx) == false)
{
result.AppendError(error.AsCString());
result.SetStatus(eReturnStatusFailed);
@@ -1617,7 +1668,12 @@ protected:
switch (short_option)
{
case 'f':
- m_funct_name = std::string(option_arg);
+ if (option_arg)
+ m_funct_name.assign(option_arg);
+ break;
+ case 'h':
+ if (option_arg)
+ m_short_help.assign(option_arg);
break;
case 's':
m_synchronicity = (ScriptedCommandSynchronicity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error);
@@ -1635,7 +1691,8 @@ protected:
void
OptionParsingStarting ()
{
- m_funct_name = "";
+ m_funct_name.clear();
+ m_short_help.clear();
m_synchronicity = eScriptedCommandSynchronicitySynchronous;
}
@@ -1652,6 +1709,7 @@ protected:
// Instance variables to hold the values for command options.
std::string m_funct_name;
+ std::string m_short_help;
ScriptedCommandSynchronicity m_synchronicity;
};
@@ -1695,6 +1753,7 @@ protected:
CommandObjectSP command_obj_sp(new CommandObjectPythonFunction (m_interpreter,
m_cmd_name,
funct_name_str.c_str(),
+ m_short_help,
m_synchronicity));
if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, true))
@@ -1748,8 +1807,9 @@ protected:
return false;
}
- // Store the command name and synchronicity in case we get multi-line input
+ // Store the options in case we get multi-line input
m_cmd_name = command.GetArgumentAtIndex(0);
+ m_short_help.assign(m_options.m_short_help);
m_synchronicity = m_options.m_synchronicity;
if (m_options.m_funct_name.empty())
@@ -1764,6 +1824,7 @@ protected:
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))
{
@@ -1782,6 +1843,7 @@ protected:
CommandOptions m_options;
std::string m_cmd_name;
+ std::string m_short_help;
ScriptedCommandSynchronicity m_synchronicity;
};
@@ -1797,6 +1859,7 @@ 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_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."},
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1949,11 +2012,11 @@ public:
"A set of commands for managing or customizing script commands.",
"command script <subcommand> [<subcommand-options>]")
{
- LoadSubCommand ("add", CommandObjectSP (new CommandObjectCommandsScriptAdd (interpreter)));
- LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsScriptDelete (interpreter)));
- LoadSubCommand ("clear", CommandObjectSP (new CommandObjectCommandsScriptClear (interpreter)));
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectCommandsScriptAdd (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsScriptDelete (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectCommandsScriptClear (interpreter)));
LoadSubCommand ("list", CommandObjectSP (new CommandObjectCommandsScriptList (interpreter)));
- LoadSubCommand ("import", CommandObjectSP (new CommandObjectCommandsScriptImport (interpreter)));
+ LoadSubCommand ("import", CommandObjectSP (new CommandObjectCommandsScriptImport (interpreter)));
}
~CommandObjectMultiwordCommandsScript ()
@@ -1978,9 +2041,10 @@ CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpret
LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter)));
LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter)));
LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsDelete (interpreter)));
LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter)));
- LoadSubCommand ("history", CommandObjectSP (new CommandObjectCommandsHistory (interpreter)));
- LoadSubCommand ("script", CommandObjectSP (new CommandObjectMultiwordCommandsScript (interpreter)));
+ LoadSubCommand ("history", CommandObjectSP (new CommandObjectCommandsHistory (interpreter)));
+ LoadSubCommand ("script", CommandObjectSP (new CommandObjectMultiwordCommandsScript (interpreter)));
}
CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands ()
diff --git a/source/Commands/CommandObjectExpression.cpp b/source/Commands/CommandObjectExpression.cpp
index 079c62ddfdff..b4c559c81cc5 100644
--- a/source/Commands/CommandObjectExpression.cpp
+++ b/source/Commands/CommandObjectExpression.cpp
@@ -281,7 +281,7 @@ CommandObjectExpression::EvaluateExpression
Target *target = exe_ctx.GetTargetPtr();
if (!target)
- target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
+ target = GetDummyTarget();
if (target)
{
@@ -425,11 +425,15 @@ CommandObjectExpression::GetMultilineExpression ()
m_expr_line_count = 0;
Debugger &debugger = GetCommandInterpreter().GetDebugger();
+ bool color_prompt = debugger.GetUseColor();
const bool multiple_lines = true; // Get multiple lines
IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
+ IOHandler::Type::Expression,
"lldb-expr", // Name of input reader for history
NULL, // No prompt
+ NULL, // Continuation prompt
multiple_lines,
+ color_prompt,
1, // Show line numbers starting at 1
*this));
diff --git a/source/Commands/CommandObjectMemory.cpp b/source/Commands/CommandObjectMemory.cpp
index bfbb296158a9..6c06ec831830 100644
--- a/source/Commands/CommandObjectMemory.cpp
+++ b/source/Commands/CommandObjectMemory.cpp
@@ -33,8 +33,10 @@
#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/MemoryHistory.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
using namespace lldb;
using namespace lldb_private;
@@ -612,7 +614,16 @@ protected:
}
size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
- size_t item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
+
+ // TODO For non-8-bit byte addressable architectures this needs to be
+ // revisited to fully support all lldb's range of formatting options.
+ // Furthermore code memory reads (for those architectures) will not
+ // be correctly formatted even w/o formatting options.
+ size_t item_byte_size =
+ target->GetArchitecture().GetDataByteSize() > 1 ?
+ target->GetArchitecture().GetDataByteSize() :
+ m_format_options.GetByteSizeValue().GetCurrentValue();
+
const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue();
if (total_byte_size == 0)
@@ -659,7 +670,7 @@ protected:
total_byte_size = end_addr - addr;
item_count = total_byte_size / item_byte_size;
}
-
+
uint32_t max_unforced_size = target->GetMaximumMemReadSize();
if (total_byte_size > max_unforced_size && !m_memory_options.m_force)
@@ -856,7 +867,8 @@ protected:
result.SetStatus(eReturnStatusSuccessFinishResult);
DataExtractor data (data_sp,
target->GetArchitecture().GetByteOrder(),
- target->GetArchitecture().GetAddressByteSize());
+ target->GetArchitecture().GetAddressByteSize(),
+ target->GetArchitecture().GetDataByteSize());
Format format = m_format_options.GetFormat();
if ( ( (format == eFormatChar) || (format == eFormatCharPrintable) )
@@ -890,7 +902,7 @@ protected:
format,
item_byte_size,
item_count,
- num_per_line,
+ num_per_line / target->GetArchitecture().GetDataByteSize(),
addr,
0,
0,
@@ -1078,7 +1090,7 @@ protected:
lldb::addr_t high_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1),LLDB_INVALID_ADDRESS,&error);
if (high_addr == LLDB_INVALID_ADDRESS || error.Fail())
{
- result.AppendError("invalid low address");
+ result.AppendError("invalid high address");
return false;
}
@@ -1667,6 +1679,96 @@ protected:
OptionGroupWriteMemory m_memory_options;
};
+//----------------------------------------------------------------------
+// Get malloc/free history of a memory address.
+//----------------------------------------------------------------------
+class CommandObjectMemoryHistory : public CommandObjectParsed
+{
+public:
+
+ CommandObjectMemoryHistory (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "memory history",
+ "Prints out the recorded stack traces for allocation/deallocation of a memory address.",
+ NULL,
+ eFlagRequiresTarget | eFlagRequiresProcess | eFlagProcessMustBePaused | eFlagProcessMustBeLaunched)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentData addr_arg;
+
+ // Define the first (and only) variant of this arg.
+ addr_arg.arg_type = eArgTypeAddress;
+ addr_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (addr_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ virtual
+ ~CommandObjectMemoryHistory ()
+ {
+ }
+
+ virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
+ {
+ return m_cmd_name.c_str();
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc == 0 || argc > 1)
+ {
+ result.AppendErrorWithFormat ("%s takes an address expression", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ Error error;
+ lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx,
+ command.GetArgumentAtIndex(0),
+ LLDB_INVALID_ADDRESS,
+ &error);
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ result.AppendError("invalid address expression");
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ Stream *output_stream = &result.GetOutputStream();
+
+ const ProcessSP &process_sp = m_exe_ctx.GetProcessSP();
+ const MemoryHistorySP &memory_history = MemoryHistory::FindPlugin(process_sp);
+
+ if (! memory_history.get())
+ {
+ result.AppendError("no available memory history provider");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ HistoryThreads thread_list = memory_history->GetHistoryThreads(addr);
+
+ for (auto thread : thread_list) {
+ thread->GetStatus(*output_stream, 0, UINT32_MAX, 0);
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+
+ return true;
+ }
+
+};
+
//-------------------------------------------------------------------------
// CommandObjectMemory
@@ -1681,6 +1783,7 @@ CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
LoadSubCommand ("find", CommandObjectSP (new CommandObjectMemoryFind (interpreter)));
LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
+ LoadSubCommand ("history", CommandObjectSP (new CommandObjectMemoryHistory (interpreter)));
}
CommandObjectMemory::~CommandObjectMemory ()
diff --git a/source/Commands/CommandObjectPlatform.cpp b/source/Commands/CommandObjectPlatform.cpp
index 9998dbdccdad..d176d52cb487 100644
--- a/source/Commands/CommandObjectPlatform.cpp
+++ b/source/Commands/CommandObjectPlatform.cpp
@@ -302,7 +302,7 @@ protected:
Stream &ostrm = result.GetOutputStream();
ostrm.Printf("Available platforms:\n");
- PlatformSP host_platform_sp (Platform::GetDefaultPlatform());
+ PlatformSP host_platform_sp (Platform::GetHostPlatform());
ostrm.Printf ("%s: %s\n",
host_platform_sp->GetPluginName().GetCString(),
host_platform_sp->GetDescription());
@@ -1347,7 +1347,6 @@ protected:
ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info,
debugger,
target,
- debugger.GetListener(),
error));
if (process_sp && process_sp->IsAlive())
{
@@ -1933,7 +1932,7 @@ public:
{
Error err;
ProcessSP remote_process_sp =
- platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), NULL, m_interpreter.GetDebugger().GetListener(), err);
+ platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), NULL, err);
if (err.Fail())
{
result.AppendError(err.AsCString());
diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp
index 6536c6ef1693..ec7b478fbecc 100644
--- a/source/Commands/CommandObjectProcess.cpp
+++ b/source/Commands/CommandObjectProcess.cpp
@@ -258,8 +258,9 @@ protected:
// Save the arguments for subsequent runs in the current target.
target->SetRunArguments (launch_args);
}
-
- Error error = target->Launch(debugger.GetListener(), m_options.launch_info);
+
+ StreamString stream;
+ Error error = target->Launch(m_options.launch_info, &stream);
if (error.Success())
{
@@ -267,6 +268,9 @@ protected:
ProcessSP process_sp (target->GetProcessSP());
if (process_sp)
{
+ const char *data = stream.GetData();
+ if (data && strlen(data) > 0)
+ result.AppendMessage(stream.GetData());
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);
@@ -564,15 +568,18 @@ protected:
if (error.Success())
{
result.SetStatus (eReturnStatusSuccessContinuingNoResult);
- StateType state = process->WaitForProcessToStop (NULL, NULL, false, listener_sp.get());
+ StreamString stream;
+ StateType state = process->WaitForProcessToStop (NULL, NULL, false, listener_sp.get(), &stream);
process->RestoreProcessEvents();
result.SetDidChangeProcessState (true);
+ if (stream.GetData())
+ result.AppendMessage(stream.GetData());
+
if (state == eStateStopped)
{
- result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
else
@@ -791,7 +798,12 @@ protected:
}
}
- Error error(process->Resume());
+ StreamString stream;
+ Error error;
+ if (synchronous_execution)
+ error = process->ResumeSynchronous (&stream);
+ else
+ error = process->Resume ();
if (error.Success())
{
@@ -803,10 +815,11 @@ protected:
result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
if (synchronous_execution)
{
- state = process->WaitForProcessToStop (NULL);
+ // If any state changed events had anything to say, add that to the result
+ if (stream.GetData())
+ result.AppendMessage(stream.GetData());
result.SetDidChangeProcessState (true);
- result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
else
diff --git a/source/Commands/CommandObjectSource.cpp b/source/Commands/CommandObjectSource.cpp
index 6b1b6aacc857..8fb03e69ac42 100644
--- a/source/Commands/CommandObjectSource.cpp
+++ b/source/Commands/CommandObjectSource.cpp
@@ -421,7 +421,7 @@ protected:
{
const bool show_inlines = true;
m_breakpoint_locations.Reset (start_file, 0, show_inlines);
- SearchFilter target_search_filter (m_exe_ctx.GetTargetSP());
+ SearchFilterForUnconstrainedSearches target_search_filter (m_exe_ctx.GetTargetSP());
target_search_filter.Search (m_breakpoint_locations);
}
@@ -682,19 +682,21 @@ protected:
m_breakpoint_locations.Clear();
const bool show_inlines = true;
m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines);
- SearchFilter target_search_filter (target->shared_from_this());
+ SearchFilterForUnconstrainedSearches target_search_filter (target->shared_from_this());
target_search_filter.Search (m_breakpoint_locations);
}
bool show_fullpaths = true;
bool show_module = true;
bool show_inlined_frames = true;
+ const bool show_function_arguments = true;
sc.DumpStopContext(&result.GetOutputStream(),
m_exe_ctx.GetBestExecutionContextScope(),
sc.line_entry.range.GetBaseAddress(),
show_fullpaths,
show_module,
- show_inlined_frames);
+ show_inlined_frames,
+ show_function_arguments);
result.GetOutputStream().EOL();
if (m_options.num_lines == 0)
@@ -741,7 +743,7 @@ protected:
{
const bool show_inlines = true;
m_breakpoint_locations.Reset (last_file_sp->GetFileSpec(), 0, show_inlines);
- SearchFilter target_search_filter (target->shared_from_this());
+ SearchFilterForUnconstrainedSearches target_search_filter (target->shared_from_this());
target_search_filter.Search (m_breakpoint_locations);
}
}
@@ -844,7 +846,7 @@ protected:
{
const bool show_inlines = true;
m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines);
- SearchFilter target_search_filter (target->shared_from_this());
+ SearchFilterForUnconstrainedSearches target_search_filter (target->shared_from_this());
target_search_filter.Search (m_breakpoint_locations);
}
else
diff --git a/source/Commands/CommandObjectSyntax.cpp b/source/Commands/CommandObjectSyntax.cpp
index d2021ea3eb19..5093c3b99339 100644
--- a/source/Commands/CommandObjectSyntax.cpp
+++ b/source/Commands/CommandObjectSyntax.cpp
@@ -69,12 +69,18 @@ CommandObjectSyntax::DoExecute (Args& command, CommandReturnObject &result)
{
std::string sub_command = command.GetArgumentAtIndex (i);
if (!cmd_obj->IsMultiwordObject())
+ {
all_okay = false;
+ break;
+ }
else
{
cmd_obj = cmd_obj->GetSubcommandObject(sub_command.c_str());
if (!cmd_obj)
+ {
all_okay = false;
+ break;
+ }
}
}
diff --git a/source/Commands/CommandObjectTarget.cpp b/source/Commands/CommandObjectTarget.cpp
index 024f7b5a0415..0d9ffda1e96b 100644
--- a/source/Commands/CommandObjectTarget.cpp
+++ b/source/Commands/CommandObjectTarget.cpp
@@ -39,6 +39,7 @@
#include "lldb/Interpreter/OptionGroupPlatform.h"
#include "lldb/Interpreter/OptionGroupUInt64.h"
#include "lldb/Interpreter/OptionGroupUUID.h"
+#include "lldb/Interpreter/OptionGroupString.h"
#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/FuncUnwinders.h"
@@ -2844,7 +2845,7 @@ public:
"Set the load addresses for one or more sections in a target module.",
"target modules load [--file <module> --uuid <uuid>] <sect-name> <address> [<sect-name> <address> ....]"),
m_option_group (interpreter),
- m_file_option (LLDB_OPT_SET_1, false, "file", 'f', 0, eArgTypeFilename, "Fullpath or basename for module to load."),
+ m_file_option (LLDB_OPT_SET_1, false, "file", 'f', 0, eArgTypeName, "Fullpath or basename for module to load.", ""),
m_slide_option(LLDB_OPT_SET_1, false, "slide", 's', 0, eArgTypeOffset, "Set the load address for all sections to be the virtual address in the file plus the offset.", 0)
{
m_option_group.Append (&m_uuid_option_group, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
@@ -2884,7 +2885,26 @@ protected:
if (m_file_option.GetOptionValue().OptionWasSet())
{
search_using_module_spec = true;
- module_spec.GetFileSpec() = m_file_option.GetOptionValue().GetCurrentValue();
+ const char *arg_cstr = m_file_option.GetOptionValue().GetCurrentValue();
+ const bool use_global_module_list = true;
+ ModuleList module_list;
+ const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, use_global_module_list);
+ if (num_matches == 1)
+ {
+ module_spec.GetFileSpec() = module_list.GetModuleAtIndex(0)->GetFileSpec();
+ }
+ else if (num_matches > 1 )
+ {
+ search_using_module_spec = false;
+ result.AppendErrorWithFormat ("more than 1 module matched by name '%s'\n", arg_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ search_using_module_spec = false;
+ result.AppendErrorWithFormat ("no object file for module '%s'\n", arg_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ }
}
if (m_uuid_option_group.GetOptionValue().OptionWasSet())
@@ -3070,7 +3090,7 @@ protected:
OptionGroupOptions m_option_group;
OptionGroupUUID m_uuid_option_group;
- OptionGroupFile m_file_option;
+ OptionGroupString m_file_option;
OptionGroupUInt64 m_slide_option;
};
@@ -3724,45 +3744,85 @@ protected:
if (func_unwinders_sp.get() == NULL)
continue;
- Address first_non_prologue_insn (func_unwinders_sp->GetFirstNonPrologueInsn(*target));
- if (first_non_prologue_insn.IsValid())
- {
- result.GetOutputStream().Printf("First non-prologue instruction is at address 0x%" PRIx64 " or offset %" PRId64 " into the function.\n", first_non_prologue_insn.GetLoadAddress(target), first_non_prologue_insn.GetLoadAddress(target) - start_addr);
- result.GetOutputStream().Printf ("\n");
- }
+ result.GetOutputStream().Printf("UNWIND PLANS for %s`%s (start addr 0x%" PRIx64 ")\n\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
UnwindPlanSP non_callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtNonCallSite(*target, *thread.get(), -1);
if (non_callsite_unwind_plan.get())
{
- result.GetOutputStream().Printf("Asynchronous (not restricted to call-sites) UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
- non_callsite_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
- result.GetOutputStream().Printf ("\n");
+ result.GetOutputStream().Printf("Asynchronous (not restricted to call-sites) UnwindPlan is '%s'\n", non_callsite_unwind_plan->GetSourceName().AsCString());
}
-
- UnwindPlanSP callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(-1);
+ UnwindPlanSP callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(*target, -1);
if (callsite_unwind_plan.get())
{
- result.GetOutputStream().Printf("Synchronous (restricted to call-sites) UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
- callsite_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
- result.GetOutputStream().Printf ("\n");
+ 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());
+ if (fast_unwind_plan.get())
+ {
+ result.GetOutputStream().Printf("Fast UnwindPlan is '%s'\n", fast_unwind_plan->GetSourceName().AsCString());
}
- UnwindPlanSP arch_default_unwind_plan = func_unwinders_sp->GetUnwindPlanArchitectureDefault(*thread.get());
- if (arch_default_unwind_plan.get())
+ result.GetOutputStream().Printf("\n");
+
+ UnwindPlanSP assembly_sp = func_unwinders_sp->GetAssemblyUnwindPlan(*target, *thread.get(), 0);
+ if (assembly_sp)
{
- result.GetOutputStream().Printf("Architecture default UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
- arch_default_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
- result.GetOutputStream().Printf ("\n");
+ result.GetOutputStream().Printf("Assembly language inspection UnwindPlan:\n");
+ assembly_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
}
+
- UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*thread.get());
- if (fast_unwind_plan.get())
+ UnwindPlanSP ehframe_sp = func_unwinders_sp->GetEHFrameUnwindPlan(*target, 0);
+ if (ehframe_sp)
{
- result.GetOutputStream().Printf("Fast UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
+ result.GetOutputStream().Printf("eh_frame UnwindPlan:\n");
+ ehframe_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
+ UnwindPlanSP ehframe_augmented_sp = func_unwinders_sp->GetEHFrameAugmentedUnwindPlan(*target, *thread.get(), 0);
+ if (ehframe_augmented_sp)
+ {
+ result.GetOutputStream().Printf("eh_frame augmented UnwindPlan:\n");
+ ehframe_augmented_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
+ UnwindPlanSP compact_unwind_sp = func_unwinders_sp->GetCompactUnwindUnwindPlan(*target, 0);
+ if (compact_unwind_sp)
+ {
+ result.GetOutputStream().Printf("Compact unwind UnwindPlan:\n");
+ compact_unwind_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
+ if (fast_unwind_plan)
+ {
+ result.GetOutputStream().Printf("Fast UnwindPlan:\n");
fast_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
- result.GetOutputStream().Printf ("\n");
+ result.GetOutputStream().Printf("\n");
}
+ ABISP abi_sp = process->GetABI();
+ if (abi_sp)
+ {
+ UnwindPlan arch_default(lldb::eRegisterKindGeneric);
+ if (abi_sp->CreateDefaultUnwindPlan (arch_default))
+ {
+ result.GetOutputStream().Printf("Arch default UnwindPlan:\n");
+ arch_default.Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
+ UnwindPlan arch_entry(lldb::eRegisterKindGeneric);
+ if (abi_sp->CreateFunctionEntryUnwindPlan (arch_entry))
+ {
+ result.GetOutputStream().Printf("Arch default at entry point UnwindPlan:\n");
+ arch_entry.Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+ }
result.GetOutputStream().Printf ("\n");
}
@@ -4999,7 +5059,7 @@ protected:
{
m_stop_hook_sp.reset();
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget();
if (target)
{
Target::StopHookSP new_hook_sp = target->CreateStopHook();
@@ -5151,7 +5211,7 @@ protected:
bool
DoExecute (Args& command, CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget();
if (target)
{
// FIXME: see if we can use the breakpoint id style parser?
@@ -5227,7 +5287,7 @@ protected:
bool
DoExecute (Args& command, CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget();
if (target)
{
// FIXME: see if we can use the breakpoint id style parser?
@@ -5297,7 +5357,7 @@ protected:
bool
DoExecute (Args& command, CommandReturnObject &result)
{
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ Target *target = GetSelectedOrDummyTarget();
if (!target)
{
result.AppendError ("invalid target\n");
diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp
index e7a8652ac898..bace4e58b4ad 100644
--- a/source/Commands/CommandObjectThread.cpp
+++ b/source/Commands/CommandObjectThread.cpp
@@ -46,7 +46,108 @@ using namespace lldb_private;
// CommandObjectThreadBacktrace
//-------------------------------------------------------------------------
-class CommandObjectThreadBacktrace : public CommandObjectParsed
+class CommandObjectIterateOverThreads : public CommandObjectParsed
+{
+public:
+ CommandObjectIterateOverThreads (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags) :
+ CommandObjectParsed (interpreter, name, help, syntax, flags)
+ {
+ }
+
+ virtual ~CommandObjectIterateOverThreads() {}
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ result.SetStatus (m_success_return);
+
+ if (command.GetArgumentCount() == 0)
+ {
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ if (!HandleOneThread (*thread, result))
+ return false;
+ }
+ else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ uint32_t idx = 0;
+ for (ThreadSP thread_sp : process->Threads())
+ {
+ if (idx != 0 && m_add_return)
+ result.AppendMessage("");
+
+ if (!HandleOneThread(*(thread_sp.get()), result))
+ return false;
+ ++idx;
+ }
+ }
+ else
+ {
+ const size_t num_args = command.GetArgumentCount();
+ Process *process = m_exe_ctx.GetProcessPtr();
+ Mutex::Locker locker (process->GetThreadList().GetMutex());
+ std::vector<ThreadSP> thread_sps;
+
+ for (size_t i = 0; i < num_args; i++)
+ {
+ bool success;
+
+ uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx));
+
+ if (!thread_sps[i])
+ {
+ result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ }
+
+ for (uint32_t i = 0; i < num_args; i++)
+ {
+ if (!HandleOneThread (*(thread_sps[i].get()), result))
+ return false;
+
+ if (i < num_args - 1 && m_add_return)
+ result.AppendMessage("");
+ }
+ }
+ return result.Succeeded();
+ }
+
+protected:
+
+ // Override this to do whatever you need to do for one thread.
+ //
+ // If you return false, the iteration will stop, otherwise it will proceed.
+ // The result is set to m_success_return (defaults to eReturnStatusSuccessFinishResult) before the iteration,
+ // so you only need to set the return status in HandleOneThread if you want to indicate an error.
+ // If m_add_return is true, a blank line will be inserted between each of the listings (except the last one.)
+
+ virtual bool
+ HandleOneThread (Thread &thread, CommandReturnObject &result) = 0;
+
+ ReturnStatus m_success_return = eReturnStatusSuccessFinishResult;
+ bool m_add_return = true;
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadBacktrace
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads
{
public:
@@ -134,7 +235,7 @@ public:
};
CommandObjectThreadBacktrace (CommandInterpreter &interpreter) :
- CommandObjectParsed (interpreter,
+ CommandObjectIterateOverThreads (interpreter,
"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,
@@ -145,18 +246,6 @@ public:
eFlagProcessMustBePaused ),
m_options(interpreter)
{
- CommandArgumentEntry arg;
- CommandArgumentData thread_idx_arg;
-
- // Define the first (and only) variant of this arg.
- thread_idx_arg.arg_type = eArgTypeThreadIndex;
- thread_idx_arg.arg_repetition = eArgRepeatStar;
-
- // There is only one variant this argument could be; put it into the argument entry.
- arg.push_back (thread_idx_arg);
-
- // Push the data for the first argument into the m_arguments vector.
- m_arguments.push_back (arg);
}
~CommandObjectThreadBacktrace()
@@ -197,106 +286,28 @@ protected:
}
virtual bool
- DoExecute (Args& command, CommandReturnObject &result)
- {
- result.SetStatus (eReturnStatusSuccessFinishResult);
+ HandleOneThread (Thread &thread, CommandReturnObject &result)
+ {
Stream &strm = result.GetOutputStream();
// Don't show source context when doing backtraces.
const uint32_t num_frames_with_source = 0;
- if (command.GetArgumentCount() == 0)
- {
- Thread *thread = m_exe_ctx.GetThreadPtr();
- // Thread::GetStatus() returns the number of frames shown.
- if (thread->GetStatus (strm,
+
+ if (!thread.GetStatus (strm,
m_options.m_start,
m_options.m_count,
num_frames_with_source))
- {
- result.SetStatus (eReturnStatusSuccessFinishResult);
- if (m_options.m_extended_backtrace)
- {
- DoExtendedBacktrace (thread, result);
- }
- }
- }
- else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0)
{
- Process *process = m_exe_ctx.GetProcessPtr();
- uint32_t idx = 0;
- for (ThreadSP thread_sp : process->Threads())
- {
- if (idx != 0)
- result.AppendMessage("");
-
- if (!thread_sp->GetStatus (strm,
- m_options.m_start,
- m_options.m_count,
- num_frames_with_source))
- {
- result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", idx);
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- if (m_options.m_extended_backtrace)
- {
- DoExtendedBacktrace (thread_sp.get(), result);
- }
-
- ++idx;
- }
+ result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", thread.GetIndexID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
}
- else
+ if (m_options.m_extended_backtrace)
{
- const size_t num_args = command.GetArgumentCount();
- Process *process = m_exe_ctx.GetProcessPtr();
- Mutex::Locker locker (process->GetThreadList().GetMutex());
- std::vector<ThreadSP> thread_sps;
-
- for (size_t i = 0; i < num_args; i++)
- {
- bool success;
-
- uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success);
- if (!success)
- {
- result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx));
-
- if (!thread_sps[i])
- {
- result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- }
-
- for (uint32_t i = 0; i < num_args; i++)
- {
- if (!thread_sps[i]->GetStatus (strm,
- m_options.m_start,
- m_options.m_count,
- num_frames_with_source))
- {
- result.AppendErrorWithFormat ("error displaying backtrace for thread: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- if (m_options.m_extended_backtrace)
- {
- DoExtendedBacktrace (thread_sps[i].get(), result);
- }
-
- if (i < num_args - 1)
- result.AppendMessage("");
- }
+ DoExtendedBacktrace (&thread, result);
}
- return result.Succeeded();
+
+ return true;
}
CommandOptions m_options;
@@ -379,6 +390,12 @@ public:
break;
}
break;
+ case 'C':
+ {
+ m_class_name.clear();
+ m_class_name.assign(option_arg);
+ }
+ break;
case 'm':
{
OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
@@ -416,6 +433,7 @@ public:
m_run_mode = eOnlyDuringStepping;
m_avoid_regexp.clear();
m_step_in_target.clear();
+ m_class_name.clear();
m_step_count = 1;
}
@@ -435,7 +453,8 @@ public:
RunMode m_run_mode;
std::string m_avoid_regexp;
std::string m_step_in_target;
- int32_t m_step_count;
+ std::string m_class_name;
+ uint32_t m_step_count;
};
CommandObjectThreadStepWithTypeAndScope (CommandInterpreter &interpreter,
@@ -520,6 +539,22 @@ protected:
}
}
+ if (m_step_type == eStepTypeScripted)
+ {
+ if (m_options.m_class_name.empty())
+ {
+ result.AppendErrorWithFormat ("empty class name for scripted step.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!m_interpreter.GetScriptInterpreter()->CheckObjectExists(m_options.m_class_name.c_str()))
+ {
+ result.AppendErrorWithFormat ("class for scripted step: \"%s\" does not exist.", m_options.m_class_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
const bool abort_other_plans = false;
const lldb::RunMode stop_other_threads = m_options.m_run_mode;
@@ -530,7 +565,7 @@ protected:
bool_stop_other_threads = false;
else if (m_options.m_run_mode == eOnlyDuringStepping)
{
- if (m_step_type == eStepTypeOut)
+ if (m_step_type == eStepTypeOut || m_step_type == eStepTypeScripted)
bool_stop_other_threads = false;
else
bool_stop_other_threads = true;
@@ -599,6 +634,12 @@ protected:
thread->GetSelectedFrameIndex(),
m_options.m_step_out_avoid_no_debug);
}
+ else if (m_step_type == eStepTypeScripted)
+ {
+ new_plan_sp = thread->QueueThreadPlanForStepScripted (abort_other_plans,
+ m_options.m_class_name.c_str(),
+ bool_stop_other_threads);
+ }
else
{
result.AppendError ("step type is not supported");
@@ -622,8 +663,15 @@ protected:
}
}
+
process->GetThreadList().SetSelectedThreadByID (thread->GetID());
- process->Resume ();
+
+ StreamString stream;
+ Error error;
+ if (synchronous_execution)
+ error = process->ResumeSynchronous (&stream);
+ else
+ error = process->Resume ();
// There is a race condition where this thread will return up the call stack to the main command handler
// and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
@@ -632,17 +680,12 @@ protected:
if (synchronous_execution)
{
- StateType state = process->WaitForProcessToStop (NULL);
-
- //EventSP event_sp;
- //StateType state = process->WaitForStateChangedEvents (NULL, event_sp);
- //while (! StateIsStoppedState (state))
- // {
- // state = process->WaitForStateChangedEvents (NULL, event_sp);
- // }
+ // If any state changed events had anything to say, add that to the result
+ if (stream.GetData())
+ result.AppendMessage(stream.GetData());
+
process->GetThreadList().SetSelectedThreadByID (thread->GetID());
result.SetDidChangeProcessState (true);
- result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
else
@@ -686,10 +729,11 @@ CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_1, false, "step-in-avoids-no-debug", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether stepping into functions will step over functions with no debug information."},
{ LLDB_OPT_SET_1, false, "step-out-avoids-no-debug", 'A', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value, if true stepping out of functions will continue to step out till it hits a function with debug information."},
-{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst."},
-{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, NULL, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."},
-{ LLDB_OPT_SET_1, false, "step-over-regexp",'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."},
-{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."},
+{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst."},
+{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, NULL, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."},
+{ LLDB_OPT_SET_1, false, "step-over-regexp", 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."},
+{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."},
+{ LLDB_OPT_SET_2, false, "python-class", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonClass, "The name of the class that will manage this step - only supported for Scripted Step."},
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -860,17 +904,25 @@ public:
}
}
+
+ StreamString stream;
+ Error error;
+ if (synchronous_execution)
+ error = process->ResumeSynchronous (&stream);
+ else
+ error = process->Resume ();
+
// We should not be holding the thread list lock when we do this.
- Error error (process->Resume());
if (error.Success())
{
result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
if (synchronous_execution)
{
- state = process->WaitForProcessToStop (NULL);
+ // If any state changed events had anything to say, add that to the result
+ if (stream.GetData())
+ result.AppendMessage(stream.GetData());
result.SetDidChangeProcessState (true);
- result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
else
@@ -1191,17 +1243,27 @@ protected:
}
+
+
process->GetThreadList().SetSelectedThreadByID (m_options.m_thread_idx);
- Error error (process->Resume ());
+
+ StreamString stream;
+ Error error;
+ if (synchronous_execution)
+ error = process->ResumeSynchronous (&stream);
+ else
+ error = process->Resume ();
+
if (error.Success())
{
result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
if (synchronous_execution)
{
- StateType state = process->WaitForProcessToStop (NULL);
+ // If any state changed events had anything to say, add that to the result
+ if (stream.GetData())
+ result.AppendMessage(stream.GetData());
result.SetDidChangeProcessState (true);
- result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
else
@@ -1358,32 +1420,22 @@ protected:
// CommandObjectThreadInfo
//-------------------------------------------------------------------------
-class CommandObjectThreadInfo : public CommandObjectParsed
+class CommandObjectThreadInfo : public CommandObjectIterateOverThreads
{
public:
CommandObjectThreadInfo (CommandInterpreter &interpreter) :
- CommandObjectParsed (interpreter,
- "thread info",
- "Show an extended summary of information about thread(s) in a process.",
- "thread info",
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused),
+ CommandObjectIterateOverThreads (interpreter,
+ "thread info",
+ "Show an extended summary of information about thread(s) in a process.",
+ "thread info",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused),
m_options (interpreter)
{
- CommandArgumentEntry arg;
- CommandArgumentData thread_idx_arg;
-
- thread_idx_arg.arg_type = eArgTypeThreadIndex;
- thread_idx_arg.arg_repetition = eArgRepeatStar;
-
- // There is only one variant this argument could be; put it into the argument entry.
- arg.push_back (thread_idx_arg);
-
- // Push the data for the first argument into the m_arguments vector.
- m_arguments.push_back (arg);
+ m_add_return = false;
}
class CommandOptions : public Options
@@ -1399,7 +1451,8 @@ public:
void
OptionParsingStarting ()
{
- m_json = false;
+ m_json_thread = false;
+ m_json_stopinfo = false;
}
virtual
@@ -1416,10 +1469,14 @@ public:
switch (short_option)
{
case 'j':
- m_json = true;
+ m_json_thread = true;
+ break;
+
+ case 's':
+ m_json_stopinfo = true;
break;
- default:
+ default:
return Error("invalid short option character '%c'", short_option);
}
@@ -1432,7 +1489,8 @@ public:
return g_option_table;
}
- bool m_json;
+ bool m_json_thread;
+ bool m_json_stopinfo;
static OptionDefinition g_option_table[];
};
@@ -1451,81 +1509,16 @@ public:
}
virtual bool
- DoExecute (Args& command, CommandReturnObject &result)
+ HandleOneThread (Thread &thread, CommandReturnObject &result)
{
- result.SetStatus (eReturnStatusSuccessFinishResult);
Stream &strm = result.GetOutputStream();
-
- if (command.GetArgumentCount() == 0)
- {
- Thread *thread = m_exe_ctx.GetThreadPtr();
- if (thread->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
- {
- result.SetStatus (eReturnStatusSuccessFinishResult);
- }
- }
- else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0)
- {
- Process *process = m_exe_ctx.GetProcessPtr();
- uint32_t idx = 0;
- for (ThreadSP thread_sp : process->Threads())
- {
- if (idx != 0)
- result.AppendMessage("");
- if (!thread_sp->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
- {
- result.AppendErrorWithFormat ("error displaying info for thread: \"0x%4.4x\"\n", idx);
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- ++idx;
- }
- }
- else
+ if (!thread.GetDescription (strm, eDescriptionLevelFull, m_options.m_json_thread, m_options.m_json_stopinfo))
{
- const size_t num_args = command.GetArgumentCount();
- Process *process = m_exe_ctx.GetProcessPtr();
- Mutex::Locker locker (process->GetThreadList().GetMutex());
- std::vector<ThreadSP> thread_sps;
-
- for (size_t i = 0; i < num_args; i++)
- {
- bool success;
-
- uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success);
- if (!success)
- {
- result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx));
-
- if (!thread_sps[i])
- {
- result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- }
-
- for (uint32_t i = 0; i < num_args; i++)
- {
- if (!thread_sps[i]->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
- {
- result.AppendErrorWithFormat ("error displaying info for thread: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- if (i < num_args - 1)
- result.AppendMessage("");
- }
-
+ result.AppendErrorWithFormat ("error displaying info for thread: \"%d\"\n", thread.GetIndexID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
}
- return result.Succeeded();
+ return true;
}
CommandOptions m_options;
@@ -1536,6 +1529,7 @@ OptionDefinition
CommandObjectThreadInfo::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_ALL, false, "json",'j', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the thread info in JSON format."},
+ { LLDB_OPT_SET_ALL, false, "stop-info",'s', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the extended stop info in JSON format."},
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1958,6 +1952,228 @@ CommandObjectThreadJump::CommandOptions::g_option_table[] =
};
//-------------------------------------------------------------------------
+// Next are the subcommands of CommandObjectMultiwordThreadPlan
+//-------------------------------------------------------------------------
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadPlanList
+//-------------------------------------------------------------------------
+class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'i':
+ {
+ m_internal = true;
+ }
+ break;
+ case 'v':
+ {
+ m_verbose = true;
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_verbose = false;
+ m_internal = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ bool m_verbose;
+ bool m_internal;
+ };
+
+ CommandObjectThreadPlanList (CommandInterpreter &interpreter) :
+ CommandObjectIterateOverThreads (interpreter,
+ "thread plan list",
+ "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 ),
+ m_options(interpreter)
+ {
+ }
+
+ ~CommandObjectThreadPlanList ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ HandleOneThread (Thread &thread, CommandReturnObject &result)
+ {
+ Stream &strm = result.GetOutputStream();
+ DescriptionLevel desc_level = eDescriptionLevelFull;
+ if (m_options.m_verbose)
+ desc_level = eDescriptionLevelVerbose;
+
+ thread.DumpThreadPlans (&strm, desc_level, m_options.m_internal, true);
+ return true;
+ }
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectThreadPlanList::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display more information about the thread plans"},
+{ LLDB_OPT_SET_1, false, "internal", 'i', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display internal as well as user thread plans"},
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
+};
+
+class CommandObjectThreadPlanDiscard : public CommandObjectParsed
+{
+public:
+ CommandObjectThreadPlanDiscard (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "thread plan discard",
+ "Discards thread plans up to and including the plan passed as the command argument."
+ "Only user visible plans can be discarded, use the index from \"thread plan list\""
+ " without the \"-i\" argument.",
+ NULL,
+ eFlagRequiresProcess |
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData plan_index_arg;
+
+ // Define the first (and only) variant of this arg.
+ plan_index_arg.arg_type = eArgTypeUnsignedInteger;
+ plan_index_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (plan_index_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual ~CommandObjectThreadPlanDiscard () {}
+
+ bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ if (args.GetArgumentCount() != 1)
+ {
+ result.AppendErrorWithFormat("Too many arguments, expected one - the thread plan index - but got %zu.",
+ args.GetArgumentCount());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ bool success;
+ uint32_t thread_plan_idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), 0, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat("Invalid thread index: \"%s\" - should be unsigned int.",
+ args.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (thread_plan_idx == 0)
+ {
+ result.AppendErrorWithFormat("You wouldn't really want me to discard the base thread plan.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Could not find User thread plan with index %s.",
+ args.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordThreadPlan
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "plan",
+ "A set of subcommands for accessing the thread plans controlling execution control on one or more threads.",
+ "thread plan <subcommand> [<subcommand objects]")
+ {
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectThreadPlanList (interpreter)));
+ LoadSubCommand ("discard", CommandObjectSP (new CommandObjectThreadPlanDiscard (interpreter)));
+ }
+
+ virtual ~CommandObjectMultiwordThreadPlan () {}
+
+
+};
+
+//-------------------------------------------------------------------------
// CommandObjectMultiwordThread
//-------------------------------------------------------------------------
@@ -2014,6 +2230,16 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter &
NULL,
eStepTypeTraceOver,
eStepScopeInstruction)));
+
+ LoadSubCommand ("step-scripted", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-scripted",
+ "Step as instructed by the script class passed in the -C option.",
+ NULL,
+ eStepTypeScripted,
+ eStepScopeSource)));
+
+ LoadSubCommand ("plan", CommandObjectSP (new CommandObjectMultiwordThreadPlan(interpreter)));
}
CommandObjectMultiwordThread::~CommandObjectMultiwordThread ()
diff --git a/source/Commands/CommandObjectType.cpp b/source/Commands/CommandObjectType.cpp
index 640fd6dd3fa4..3a4c60c00f8b 100644
--- a/source/Commands/CommandObjectType.cpp
+++ b/source/Commands/CommandObjectType.cpp
@@ -16,6 +16,7 @@
#include <ctype.h>
// C++ Includes
+#include <functional>
#include "llvm/ADT/StringRef.h"
@@ -31,6 +32,11 @@
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/Options.h"
#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadList.h"
using namespace lldb;
using namespace lldb_private;
@@ -2465,22 +2471,7 @@ protected:
if (argc == 1 && strcmp(command.GetArgumentAtIndex(0),"*") == 0)
{
- // we want to make sure to enable "system" last and "default" first
- DataVisualization::Categories::Enable(ConstString("default"), TypeCategoryMap::First);
- uint32_t num_categories = DataVisualization::Categories::GetCount();
- for (uint32_t i = 0; i < num_categories; i++)
- {
- lldb::TypeCategoryImplSP category_sp = DataVisualization::Categories::GetCategoryAtIndex(i);
- if (category_sp)
- {
- if ( ::strcmp(category_sp->GetName(), "system") == 0 ||
- ::strcmp(category_sp->GetName(), "default") == 0 )
- continue;
- else
- DataVisualization::Categories::Enable(category_sp, TypeCategoryMap::Default);
- }
- }
- DataVisualization::Categories::Enable(ConstString("system"), TypeCategoryMap::Last);
+ DataVisualization::Categories::EnableStar();
}
else
{
@@ -2630,14 +2621,7 @@ protected:
if (argc == 1 && strcmp(command.GetArgumentAtIndex(0),"*") == 0)
{
- uint32_t num_categories = DataVisualization::Categories::GetCount();
- for (uint32_t i = 0; i < num_categories; i++)
- {
- lldb::TypeCategoryImplSP category_sp = DataVisualization::Categories::GetCategoryAtIndex(i);
- // no need to check if the category is enabled - disabling a disabled category has no effect
- if (category_sp)
- DataVisualization::Categories::Disable(category_sp);
- }
+ DataVisualization::Categories::DisableStar();
}
else
{
@@ -4253,6 +4237,84 @@ CommandObjectTypeFilterAdd::CommandOptions::g_option_table[] =
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
+template <typename FormatterType>
+class CommandObjectFormatterInfo : public CommandObjectRaw
+{
+public:
+ typedef std::function<typename FormatterType::SharedPointer(ValueObject&)> DiscoveryFunction;
+ CommandObjectFormatterInfo (CommandInterpreter &interpreter,
+ const char* formatter_name,
+ DiscoveryFunction discovery_func) :
+ CommandObjectRaw(interpreter,
+ nullptr,
+ nullptr,
+ nullptr,
+ eFlagRequiresFrame),
+ m_formatter_name(formatter_name ? formatter_name : ""),
+ m_discovery_function(discovery_func)
+ {
+ StreamString name;
+ name.Printf("type %s info", formatter_name);
+ SetCommandName(name.GetData());
+ StreamString help;
+ help.Printf("This command evaluates the provided expression and shows which %s is applied to the resulting value (if any).", formatter_name);
+ SetHelp(help.GetData());
+ StreamString syntax;
+ syntax.Printf("type %s info <expr>", formatter_name);
+ SetSyntax(syntax.GetData());
+ }
+
+ virtual
+ ~CommandObjectFormatterInfo ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ auto target_sp = m_interpreter.GetDebugger().GetSelectedTarget();
+ auto frame_sp = target_sp->GetProcessSP()->GetThreadList().GetSelectedThread()->GetSelectedFrame();
+ ValueObjectSP result_valobj_sp;
+ EvaluateExpressionOptions options;
+ lldb::ExpressionResults expr_result = target_sp->EvaluateExpression(command, frame_sp.get(), result_valobj_sp, options);
+ if (expr_result == eExpressionCompleted && result_valobj_sp)
+ {
+ result_valobj_sp = result_valobj_sp->GetQualifiedRepresentationIfAvailable(target_sp->GetPreferDynamicValue(), target_sp->GetEnableSyntheticValue());
+ typename FormatterType::SharedPointer formatter_sp = m_discovery_function(*result_valobj_sp);
+ if (formatter_sp)
+ {
+ std::string description(formatter_sp->GetDescription());
+ result.AppendMessageWithFormat("%s applied to (%s) %s is: %s\n",
+ m_formatter_name.c_str(),
+ result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>"),
+ command,
+ description.c_str());
+ result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendMessageWithFormat("no %s applies to (%s) %s\n",
+ m_formatter_name.c_str(),
+ result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>"),
+ command);
+ result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
+ }
+ return true;
+ }
+ else
+ {
+ result.AppendError("failed to evaluate expression");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ }
+
+private:
+ std::string m_formatter_name;
+ DiscoveryFunction m_discovery_function;
+};
+
class CommandObjectTypeFormat : public CommandObjectMultiword
{
public:
@@ -4266,6 +4328,11 @@ public:
LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeFormatClear (interpreter)));
LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeFormatDelete (interpreter)));
LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeFormatList (interpreter)));
+ LoadSubCommand ("info", CommandObjectSP (new CommandObjectFormatterInfo<TypeFormatImpl>(interpreter,
+ "format",
+ [](ValueObject& valobj) -> TypeFormatImpl::SharedPointer {
+ return valobj.GetValueFormat();
+ })));
}
@@ -4289,6 +4356,11 @@ public:
LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSynthClear (interpreter)));
LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSynthDelete (interpreter)));
LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSynthList (interpreter)));
+ LoadSubCommand ("info", CommandObjectSP (new CommandObjectFormatterInfo<SyntheticChildren>(interpreter,
+ "synthetic",
+ [](ValueObject& valobj) -> SyntheticChildren::SharedPointer {
+ return valobj.GetSyntheticChildren();
+ })));
}
@@ -4354,6 +4426,11 @@ public:
LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSummaryClear (interpreter)));
LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSummaryDelete (interpreter)));
LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSummaryList (interpreter)));
+ LoadSubCommand ("info", CommandObjectSP (new CommandObjectFormatterInfo<TypeSummaryImpl>(interpreter,
+ "summary",
+ [](ValueObject& valobj) -> TypeSummaryImpl::SharedPointer {
+ return valobj.GetSummaryFormat();
+ })));
}
diff --git a/source/Commands/CommandObjectWatchpointCommand.cpp b/source/Commands/CommandObjectWatchpointCommand.cpp
index f46db7a6a82b..275ee925adcc 100644
--- a/source/Commands/CommandObjectWatchpointCommand.cpp
+++ b/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -279,17 +279,16 @@ but do NOT enter more than one command per line. \n" );
result.SetImmediateOutputStream (output_stream);
result.SetImmediateErrorStream (error_stream);
- bool stop_on_continue = true;
- bool echo_commands = false;
- bool print_results = true;
+ CommandInterpreterRunOptions options;
+ options.SetStopOnContinue (true);
+ options.SetStopOnError (data->stop_on_error);
+ options.SetEchoCommands (false);
+ options.SetPrintResults (true);
+ options.SetAddToHistory (false);
debugger.GetCommandInterpreter().HandleCommands (commands,
&exe_ctx,
- stop_on_continue,
- data->stop_on_error,
- echo_commands,
- print_results,
- eLazyBoolNo,
+ options,
result);
result.GetImmediateOutputStream()->Flush();
result.GetImmediateErrorStream()->Flush();
diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp
index fa9197d12b70..a79becbf49c4 100644
--- a/source/Core/Address.cpp
+++ b/source/Core/Address.cpp
@@ -433,7 +433,9 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
case DumpStyleModuleWithFileAddress:
if (section_sp)
- s->Printf("%s[", section_sp->GetModule()->GetFileSpec().GetFilename().AsCString());
+ {
+ s->Printf("%s[", section_sp->GetModule()->GetFileSpec().GetFilename().AsCString("<Unknown>"));
+ }
// Fall through
case DumpStyleFileAddress:
{
@@ -465,6 +467,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
case DumpStyleResolvedDescription:
case DumpStyleResolvedDescriptionNoModule:
+ case DumpStyleResolvedDescriptionNoFunctionArguments:
if (IsSectionOffset())
{
uint32_t pointer_size = 4;
@@ -550,7 +553,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);
+ func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false, true);
if (ReadAddress (exe_scope, cstr_addr, pointer_size, so_addr))
{
#if VERBOSE_OUTPUT
@@ -633,7 +636,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);
+ pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false, true);
}
}
}
@@ -658,6 +661,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
const bool show_module = (style == DumpStyleResolvedDescription);
const bool show_fullpaths = false;
const bool show_inlined_frames = true;
+ const bool show_function_arguments = (style != DumpStyleResolvedDescriptionNoFunctionArguments);
if (sc.function == NULL && sc.symbol != NULL)
{
// If we have just a symbol make sure it is in the right section
@@ -679,7 +683,8 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
*this,
show_fullpaths,
show_module,
- show_inlined_frames);
+ show_inlined_frames,
+ show_function_arguments);
}
else
{
diff --git a/source/Core/AddressRange.cpp b/source/Core/AddressRange.cpp
index 3505d56b43e2..ac64833884ee 100644
--- a/source/Core/AddressRange.cpp
+++ b/source/Core/AddressRange.cpp
@@ -179,7 +179,7 @@ AddressRange::Dump(Stream *s, Target *target, Address::DumpStyle style, Address:
{
ModuleSP module_sp (GetBaseAddress().GetModule());
if (module_sp)
- s->Printf("%s", module_sp->GetFileSpec().GetFilename().AsCString());
+ s->Printf("%s", module_sp->GetFileSpec().GetFilename().AsCString("<Unknown>"));
}
s->AddressRange(vmaddr, vmaddr + GetByteSize(), addr_size);
return true;
diff --git a/source/Core/AddressResolverFileLine.cpp b/source/Core/AddressResolverFileLine.cpp
index f7004c8bb089..6089abd76cbc 100644
--- a/source/Core/AddressResolverFileLine.cpp
+++ b/source/Core/AddressResolverFileLine.cpp
@@ -96,7 +96,7 @@ AddressResolverFileLine::GetDepth()
void
AddressResolverFileLine::GetDescription (Stream *s)
{
- s->Printf ("File and line address - file: \"%s\" line: %u", m_file_spec.GetFilename().AsCString(), m_line_number);
+ s->Printf ("File and line address - file: \"%s\" line: %u", m_file_spec.GetFilename().AsCString("<Unknown>"), m_line_number);
}
diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp
index 5f010f066408..e7a5e489af19 100644
--- a/source/Core/ArchSpec.cpp
+++ b/source/Core/ArchSpec.cpp
@@ -24,6 +24,11 @@
#include "lldb/Host/Endian.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "Plugins/Process/Utility/ARMDefines.h"
+#include "Plugins/Process/Utility/InstructionUtils.h"
using namespace lldb;
using namespace lldb_private;
@@ -84,7 +89,7 @@ static const CoreDefinition g_core_definitions[] =
{ eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64 , "mips64" },
- { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "ppc" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "powerpc" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc601 , "ppc601" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc602 , "ppc602" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc603 , "ppc603" },
@@ -98,7 +103,7 @@ static const CoreDefinition g_core_definitions[] =
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc7450 , "ppc7450" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc970 , "ppc970" },
- { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_generic , "ppc64" },
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_generic , "powerpc64" },
{ eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_ppc970_64 , "ppc970-64" },
{ eByteOrderLittle, 4, 4, 4, llvm::Triple::sparc , ArchSpec::eCore_sparc_generic , "sparc" },
@@ -118,7 +123,6 @@ static const CoreDefinition g_core_definitions[] =
{ eByteOrderLittle, 4, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach32 , "unknown-mach-32" },
{ eByteOrderLittle, 8, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach64 , "unknown-mach-64" },
- { eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba , "kalimba" },
{ eByteOrderBig , 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba3 , "kalimba3" },
{ eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba4 , "kalimba4" },
{ eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba5 , "kalimba5" }
@@ -195,10 +199,10 @@ static const ArchDefinitionEntry g_macho_arch_entries[] =
{ ArchSpec::eCore_arm_armv7k , llvm::MachO::CPU_TYPE_ARM , 12 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_arm_armv7m , llvm::MachO::CPU_TYPE_ARM , 15 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_arm_armv7em , llvm::MachO::CPU_TYPE_ARM , 16 , UINT32_MAX , SUBTYPE_MASK },
- { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , CPU_ANY, UINT32_MAX , SUBTYPE_MASK },
- { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 0 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 1 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 0 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 13 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , CPU_ANY, UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_thumb , llvm::MachO::CPU_TYPE_ARM , 0 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_thumbv4t , llvm::MachO::CPU_TYPE_ARM , 5 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_thumbv5 , llvm::MachO::CPU_TYPE_ARM , 7 , UINT32_MAX , SUBTYPE_MASK },
@@ -264,11 +268,9 @@ static const ArchDefinitionEntry g_elf_arch_entries[] =
{ ArchSpec::eCore_x86_64_x86_64 , llvm::ELF::EM_X86_64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // AMD64
{ ArchSpec::eCore_mips64 , llvm::ELF::EM_MIPS , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // MIPS
{ ArchSpec::eCore_hexagon_generic , llvm::ELF::EM_HEXAGON, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // HEXAGON
- { ArchSpec::eCore_kalimba , llvm::ELF::EM_CSR_KALIMBA, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
- { ArchSpec::eCore_kalimba3 , llvm::ELF::EM_CSR_KALIMBA, 3, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
- { ArchSpec::eCore_kalimba4 , llvm::ELF::EM_CSR_KALIMBA, 4, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
- { ArchSpec::eCore_kalimba5 , llvm::ELF::EM_CSR_KALIMBA, 5, 0xFFFFFFFFu, 0xFFFFFFFFu } // KALIMBA
-
+ { 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
+ { ArchSpec::eCore_kalimba5 , llvm::ELF::EM_CSR_KALIMBA, llvm::Triple::KalimbaSubArch_v5, 0xFFFFFFFFu, 0xFFFFFFFFu } // KALIMBA
};
static const ArchDefinition g_elf_arch_def = {
@@ -503,11 +505,11 @@ ArchSpec::GetDataByteSize () const
switch (m_core)
{
case eCore_kalimba3:
- return 3;
+ return 4;
case eCore_kalimba4:
return 1;
case eCore_kalimba5:
- return 3;
+ return 4;
default:
return 1;
}
@@ -1036,16 +1038,6 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
}
break;
- case ArchSpec::eCore_kalimba:
- case ArchSpec::eCore_kalimba3:
- case ArchSpec::eCore_kalimba4:
- case ArchSpec::eCore_kalimba5:
- if (core2 >= ArchSpec::kCore_kalimba_first && core2 <= ArchSpec::kCore_kalimba_last)
- {
- return true;
- }
- break;
-
case ArchSpec::eCore_arm_armv8:
if (!enforce_exact_match)
{
@@ -1094,3 +1086,108 @@ lldb_private::operator<(const ArchSpec& lhs, const ArchSpec& rhs)
const ArchSpec::Core rhs_core = rhs.GetCore ();
return lhs_core < rhs_core;
}
+
+static void
+StopInfoOverrideCallbackTypeARM(lldb_private::Thread &thread)
+{
+ // We need to check if we are stopped in Thumb mode in a IT instruction
+ // and detect if the condition doesn't pass. If this is the case it means
+ // we won't actually execute this instruction. If this happens we need to
+ // clear the stop reason to no thread plans think we are stopped for a
+ // reason and the plans should keep going.
+ //
+ // We do this because when single stepping many ARM processes, debuggers
+ // often use the BVR/BCR registers that says "stop when the PC is not
+ // equal to its current value". This method of stepping means we can end
+ // up stopping on instructions inside an if/then block that wouldn't get
+ // executed. By fixing this we can stop the debugger from seeming like
+ // you stepped through both the "if" _and_ the "else" clause when source
+ // level stepping because the debugger stops regardless due to the BVR/BCR
+ // triggering a stop.
+ //
+ // It also means we can set breakpoints on instructions inside an an
+ // if/then block and correctly skip them if we use the BKPT instruction.
+ // The ARM and Thumb BKPT instructions are unconditional even when executed
+ // in a Thumb IT block.
+ //
+ // If your debugger inserts software traps in ARM/Thumb code, it will
+ // need to use 16 and 32 bit instruction for 16 and 32 bit thumb
+ // instructions respectively. If your debugger inserts a 16 bit thumb
+ // trap on top of a 32 bit thumb instruction for an opcode that is inside
+ // an if/then, it will change the it/then to conditionally execute your
+ // 16 bit trap and then cause your program to crash if it executes the
+ // trailing 16 bits (the second half of the 32 bit thumb instruction you
+ // partially overwrote).
+
+ RegisterContextSP reg_ctx_sp (thread.GetRegisterContext());
+ if (reg_ctx_sp)
+ {
+ const uint32_t cpsr = reg_ctx_sp->GetFlags(0);
+ if (cpsr != 0)
+ {
+ // Read the J and T bits to get the ISETSTATE
+ const uint32_t J = Bit32(cpsr, 24);
+ const uint32_t T = Bit32(cpsr, 5);
+ const uint32_t ISETSTATE = J << 1 | T;
+ if (ISETSTATE == 0)
+ {
+ // NOTE: I am pretty sure we want to enable the code below
+ // that detects when we stop on an instruction in ARM mode
+ // that is conditional and the condition doesn't pass. This
+ // can happen if you set a breakpoint on an instruction that
+ // is conditional. We currently will _always_ stop on the
+ // instruction which is bad. You can also run into this while
+ // single stepping and you could appear to run code in the "if"
+ // and in the "else" clause because it would stop at all of the
+ // conditional instructions in both.
+ // In such cases, we really don't want to stop at this location.
+ // I will check with the lldb-dev list first before I enable this.
+#if 0
+ // ARM mode: check for condition on intsruction
+ const addr_t pc = reg_ctx_sp->GetPC();
+ Error error;
+ // If we fail to read the opcode we will get UINT64_MAX as the
+ // result in "opcode" which we can use to detect if we read a
+ // valid opcode.
+ const uint64_t opcode = thread.GetProcess()->ReadUnsignedIntegerFromMemory(pc, 4, UINT64_MAX, error);
+ if (opcode <= UINT32_MAX)
+ {
+ const uint32_t condition = Bits32((uint32_t)opcode, 31, 28);
+ if (ARMConditionPassed(condition, cpsr) == false)
+ {
+ // We ARE stopped on an ARM instruction whose condition doesn't
+ // pass so this instruction won't get executed.
+ // Regardless of why it stopped, we need to clear the stop info
+ thread.SetStopInfo (StopInfoSP());
+ }
+ }
+#endif
+ }
+ else if (ISETSTATE == 1)
+ {
+ // Thumb mode
+ const uint32_t ITSTATE = Bits32 (cpsr, 15, 10) << 2 | Bits32 (cpsr, 26, 25);
+ if (ITSTATE != 0)
+ {
+ const uint32_t condition = Bits32(ITSTATE, 7, 4);
+ if (ARMConditionPassed(condition, cpsr) == false)
+ {
+ // We ARE stopped in a Thumb IT instruction on an instruction whose
+ // condition doesn't pass so this instruction won't get executed.
+ // Regardless of why it stopped, we need to clear the stop info
+ thread.SetStopInfo (StopInfoSP());
+ }
+ }
+ }
+ }
+ }
+}
+
+ArchSpec::StopInfoOverrideCallbackType
+ArchSpec::GetStopInfoOverrideCallback () const
+{
+ const llvm::Triple::ArchType machine = GetMachine();
+ if (machine == llvm::Triple::arm)
+ return StopInfoOverrideCallbackTypeARM;
+ return NULL;
+}
diff --git a/source/Core/Communication.cpp b/source/Core/Communication.cpp
index d71c9881a6f3..ea84843fe0b3 100644
--- a/source/Core/Communication.cpp
+++ b/source/Core/Communication.cpp
@@ -18,6 +18,8 @@
#include "lldb/Core/Timer.h"
#include "lldb/Core/Event.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/ThreadLauncher.h"
#include <string.h>
using namespace lldb;
@@ -36,7 +38,6 @@ Communication::GetStaticBroadcasterClass ()
Communication::Communication(const char *name) :
Broadcaster (NULL, name),
m_connection_sp (),
- m_read_thread (LLDB_INVALID_HOST_THREAD),
m_read_thread_enabled (false),
m_bytes(),
m_bytes_mutex (Mutex::eMutexTypeRecursive),
@@ -232,7 +233,7 @@ Communication::StartReadThread (Error *error_ptr)
if (error_ptr)
error_ptr->Clear();
- if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ if (m_read_thread.IsJoinable())
return true;
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
@@ -243,8 +244,8 @@ 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 = Host::ThreadCreate (thread_name, Communication::ReadThread, this, error_ptr);
- if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ m_read_thread = ThreadLauncher::LaunchThread(thread_name, Communication::ReadThread, this, error_ptr);
+ if (!m_read_thread.IsJoinable())
m_read_thread_enabled = false;
return m_read_thread_enabled;
}
@@ -252,7 +253,7 @@ Communication::StartReadThread (Error *error_ptr)
bool
Communication::StopReadThread (Error *error_ptr)
{
- if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ if (!m_read_thread.IsJoinable())
return true;
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
@@ -262,22 +263,20 @@ Communication::StopReadThread (Error *error_ptr)
BroadcastEvent (eBroadcastBitReadThreadShouldExit, NULL);
- //Host::ThreadCancel (m_read_thread, error_ptr);
+ // error = m_read_thread.Cancel();
- bool status = Host::ThreadJoin (m_read_thread, NULL, error_ptr);
- m_read_thread = LLDB_INVALID_HOST_THREAD;
- return status;
+ Error error = m_read_thread.Join(nullptr);
+ return error.Success();
}
bool
Communication::JoinReadThread (Error *error_ptr)
{
- if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ if (!m_read_thread.IsJoinable())
return true;
- bool success = Host::ThreadJoin (m_read_thread, NULL, error_ptr);
- m_read_thread = LLDB_INVALID_HOST_THREAD;
- return success;
+ Error error = m_read_thread.Join(nullptr);
+ return error.Success();
}
size_t
diff --git a/source/Core/Connection.cpp b/source/Core/Connection.cpp
index 3c9bb8b1b7ed..3f740a1ed82a 100644
--- a/source/Core/Connection.cpp
+++ b/source/Core/Connection.cpp
@@ -13,6 +13,12 @@
// Project includes
#include "lldb/Core/Connection.h"
+#if defined(_WIN32)
+#include "lldb/Host/windows/ConnectionGenericFileWindows.h"
+#endif
+
+#include "lldb/Host/ConnectionFileDescriptor.h"
+
using namespace lldb_private;
Connection::Connection ()
@@ -22,3 +28,13 @@ Connection::Connection ()
Connection::~Connection ()
{
}
+
+Connection *
+Connection::CreateDefaultConnection(const char *url)
+{
+#if defined(_WIN32)
+ if (strstr(url, "file://") == url)
+ return new ConnectionGenericFile();
+#endif
+ return new ConnectionFileDescriptor();
+}
diff --git a/source/Core/ConnectionSharedMemory.cpp b/source/Core/ConnectionSharedMemory.cpp
index 5db3d687cdb2..1cbee20cd94a 100644
--- a/source/Core/ConnectionSharedMemory.cpp
+++ b/source/Core/ConnectionSharedMemory.cpp
@@ -6,6 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#ifndef __ANDROID_NDK__
#include "lldb/Core/ConnectionSharedMemory.h"
@@ -156,3 +157,4 @@ ConnectionSharedMemory::Open (bool create, const char *name, size_t size, Error
return eConnectionStatusError;
}
+#endif // __ANDROID_NDK__
diff --git a/source/Core/ConstString.cpp b/source/Core/ConstString.cpp
index 5657b483a495..37d24e0dec00 100644
--- a/source/Core/ConstString.cpp
+++ b/source/Core/ConstString.cpp
@@ -11,6 +11,8 @@
#include "lldb/Host/Mutex.h"
#include "llvm/ADT/StringMap.h"
+#include <mutex>
+
using namespace lldb_private;
@@ -93,7 +95,7 @@ public:
{
Mutex::Locker locker (m_mutex);
llvm::StringRef string_ref (cstr, cstr_len);
- StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
+ StringPoolEntryType& entry = *m_string_map.insert (std::make_pair (string_ref, (StringPoolValueType)NULL)).first;
return entry.getKeyData();
}
return NULL;
@@ -105,7 +107,7 @@ public:
if (string_ref.data())
{
Mutex::Locker locker (m_mutex);
- StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
+ StringPoolEntryType& entry = *m_string_map.insert (std::make_pair (string_ref, (StringPoolValueType)NULL)).first;
return entry.getKeyData();
}
return NULL;
@@ -118,7 +120,7 @@ public:
{
Mutex::Locker locker (m_mutex);
// Make string pool entry with the mangled counterpart already set
- StringPoolEntryType& entry = m_string_map.GetOrCreateValue (llvm::StringRef (demangled_cstr), mangled_ccstr);
+ StringPoolEntryType& entry = *m_string_map.insert (std::make_pair (llvm::StringRef (demangled_cstr), mangled_ccstr)).first;
// Extract the const version of the demangled_cstr
const char *demangled_ccstr = entry.getKeyData();
@@ -184,25 +186,16 @@ protected:
// we can't guarantee that some objects won't get destroyed after the
// global destructor chain is run, and trying to make sure no destructors
// touch ConstStrings is difficult. So we leak the pool instead.
-//
-// FIXME: If we are going to keep it this way we should come up with some
-// abstraction to "pthread_once" so we don't have to check the pointer
-// every time.
//----------------------------------------------------------------------
static Pool &
StringPool()
{
- static Mutex g_pool_initialization_mutex;
+ static std::once_flag g_pool_initialization_flag;
static Pool *g_string_pool = NULL;
- if (g_string_pool == NULL)
- {
- Mutex::Locker initialization_locker(g_pool_initialization_mutex);
- if (g_string_pool == NULL)
- {
- g_string_pool = new Pool();
- }
- }
+ std::call_once(g_pool_initialization_flag, [] () {
+ g_string_pool = new Pool();
+ });
return *g_string_pool;
}
diff --git a/source/Core/DataExtractor.cpp b/source/Core/DataExtractor.cpp
index a0958bd6b1c6..6e1d63095cf3 100644
--- a/source/Core/DataExtractor.cpp
+++ b/source/Core/DataExtractor.cpp
@@ -22,7 +22,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/MathExtras.h"
-
+#include "llvm/Support/MD5.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
@@ -132,7 +132,8 @@ DataExtractor::DataExtractor () :
m_end (NULL),
m_byte_order(lldb::endian::InlHostByteOrder()),
m_addr_size (4),
- m_data_sp ()
+ m_data_sp (),
+ m_target_byte_size(1)
{
}
@@ -140,12 +141,13 @@ DataExtractor::DataExtractor () :
// This constructor allows us to use data that is owned by someone else.
// The data must stay around as long as this object is valid.
//----------------------------------------------------------------------
-DataExtractor::DataExtractor (const void* data, offset_t length, ByteOrder endian, uint32_t addr_size) :
+DataExtractor::DataExtractor (const void* data, offset_t length, ByteOrder endian, uint32_t addr_size, uint32_t target_byte_size/*=1*/) :
m_start ((uint8_t*)data),
m_end ((uint8_t*)data + length),
m_byte_order(endian),
m_addr_size (addr_size),
- m_data_sp ()
+ m_data_sp (),
+ m_target_byte_size(target_byte_size)
{
}
@@ -156,12 +158,13 @@ DataExtractor::DataExtractor (const void* data, offset_t length, ByteOrder endia
// as long as any DataExtractor objects exist that have a reference to
// this data.
//----------------------------------------------------------------------
-DataExtractor::DataExtractor (const DataBufferSP& data_sp, ByteOrder endian, uint32_t addr_size) :
+DataExtractor::DataExtractor (const DataBufferSP& data_sp, ByteOrder endian, uint32_t addr_size, uint32_t target_byte_size/*=1*/) :
m_start (NULL),
m_end (NULL),
m_byte_order(endian),
m_addr_size (addr_size),
- m_data_sp ()
+ m_data_sp (),
+ m_target_byte_size(target_byte_size)
{
SetData (data_sp);
}
@@ -173,12 +176,13 @@ DataExtractor::DataExtractor (const DataBufferSP& data_sp, ByteOrder endian, uin
// as any object contains a reference to that data. The endian
// swap and address size settings are copied from "data".
//----------------------------------------------------------------------
-DataExtractor::DataExtractor (const DataExtractor& data, offset_t offset, offset_t length) :
+DataExtractor::DataExtractor (const DataExtractor& data, offset_t offset, offset_t length, uint32_t target_byte_size/*=1*/) :
m_start(NULL),
m_end(NULL),
m_byte_order(data.m_byte_order),
m_addr_size(data.m_addr_size),
- m_data_sp()
+ m_data_sp(),
+ m_target_byte_size(target_byte_size)
{
if (data.ValidOffset(offset))
{
@@ -194,7 +198,8 @@ DataExtractor::DataExtractor (const DataExtractor& rhs) :
m_end (rhs.m_end),
m_byte_order (rhs.m_byte_order),
m_addr_size (rhs.m_addr_size),
- m_data_sp (rhs.m_data_sp)
+ m_data_sp (rhs.m_data_sp),
+ m_target_byte_size(rhs.m_target_byte_size)
{
}
@@ -1480,7 +1485,9 @@ DataExtractor::Dump (Stream *s,
s->EOL();
}
if (base_addr != LLDB_INVALID_ADDRESS)
- s->Printf ("0x%8.8" PRIx64 ": ", (uint64_t)(base_addr + (offset - start_offset)));
+ s->Printf ("0x%8.8" PRIx64 ": ",
+ (uint64_t)(base_addr + (offset - start_offset)/m_target_byte_size ));
+
line_start_offset = offset;
}
else
@@ -1535,6 +1542,7 @@ DataExtractor::Dump (Stream *s,
{
s->Printf ("%2.2x", GetU8(&offset));
}
+
// Put an extra space between the groups of bytes if more than one
// is being dumped in a group (item_byte_size is more than 1).
if (item_byte_size > 1)
@@ -2230,3 +2238,27 @@ DataExtractor::Append(void* buf, offset_t length)
return true;
}
+
+void
+DataExtractor::Checksum (llvm::SmallVectorImpl<uint8_t> &dest,
+ uint64_t max_data)
+{
+ if (max_data == 0)
+ max_data = GetByteSize();
+ else
+ max_data = std::min(max_data, GetByteSize());
+
+ llvm::MD5 md5;
+
+ const llvm::ArrayRef<uint8_t> data(GetDataStart(),max_data);
+ md5.update(data);
+
+ llvm::MD5::MD5Result result;
+ md5.final(result);
+
+ dest.resize(16);
+ std::copy(result,
+ result+16,
+ dest.begin());
+}
+
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
index 178296347677..c7342ade6cad 100644
--- a/source/Core/Debugger.cpp
+++ b/source/Core/Debugger.cpp
@@ -18,7 +18,6 @@
#include "llvm/ADT/StringRef.h"
#include "lldb/lldb-private.h"
-#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -34,8 +33,10 @@
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Terminal.h"
+#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/OptionValueSInt64.h"
#include "lldb/Interpreter/OptionValueString.h"
@@ -44,6 +45,8 @@
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -61,6 +64,7 @@ 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;
#pragma mark Static Functions
@@ -121,12 +125,13 @@ 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}>}: "
static PropertyDefinition
g_properties[] =
{
{ "auto-confirm", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true all confirmation prompts will receive their default reply." },
+{ "disassembly-format", OptionValue::eTypeString , true, 0 , DEFAULT_DISASSEMBLY_FORMAT, NULL, "The default disassembly format string to use when disassembling instruction sequences." },
{ "frame-format", OptionValue::eTypeString , true, 0 , DEFAULT_FRAME_FORMAT, NULL, "The default frame format string to use when displaying stack frame information for threads." },
{ "notify-void", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Notify the user explicitly if an expression returns void (default: false)." },
{ "prompt", OptionValue::eTypeString , true, OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", NULL, "The debugger command line prompt displayed for the user." },
@@ -139,7 +144,8 @@ g_properties[] =
{ "thread-format", OptionValue::eTypeString , true, 0 , DEFAULT_THREAD_FORMAT, NULL, "The default thread format string to use when displaying thread information." },
{ "use-external-editor", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Whether to use an external editor or not." },
{ "use-color", OptionValue::eTypeBoolean, true, true , NULL, NULL, "Whether to use Ansi color codes or not." },
-{ "auto-one-line-summaries", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." },
+{ "auto-one-line-summaries", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." },
+{ "escape-non-printables", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will automatically escape non-printable and escape characters when formatting strings." },
{ NULL, OptionValue::eTypeInvalid, true, 0 , NULL, NULL, NULL }
};
@@ -147,6 +153,7 @@ g_properties[] =
enum
{
ePropertyAutoConfirm = 0,
+ ePropertyDisassemblyFormat,
ePropertyFrameFormat,
ePropertyNotiftVoid,
ePropertyPrompt,
@@ -159,7 +166,8 @@ enum
ePropertyThreadFormat,
ePropertyUseExternalEditor,
ePropertyUseColor,
- ePropertyAutoOneLineSummaries
+ ePropertyAutoOneLineSummaries,
+ ePropertyEscapeNonPrintables
};
Debugger::LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL;
@@ -171,6 +179,7 @@ Debugger::SetPropertyValue (const ExecutionContext *exe_ctx,
const char *value)
{
bool is_load_script = strcmp(property_path,"target.load-script-from-symbol-file") == 0;
+ bool is_escape_non_printables = strcmp(property_path, "escape-non-printables") == 0;
TargetSP target_sp;
LoadScriptFromSymFile load_script_old_value;
if (is_load_script && exe_ctx->GetTargetSP())
@@ -218,6 +227,10 @@ Debugger::SetPropertyValue (const ExecutionContext *exe_ctx,
}
}
}
+ else if (is_escape_non_printables)
+ {
+ DataVisualization::ForceUpdate();
+ }
}
return error;
}
@@ -230,6 +243,13 @@ Debugger::GetAutoConfirm () const
}
const char *
+Debugger::GetDisassemblyFormat() const
+{
+ const uint32_t idx = ePropertyDisassemblyFormat;
+ return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value);
+}
+
+const char *
Debugger::GetFrameFormat() const
{
const uint32_t idx = ePropertyFrameFormat;
@@ -353,7 +373,13 @@ Debugger::GetAutoOneLineSummaries () const
{
const uint32_t idx = ePropertyAutoOneLineSummaries;
return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true);
+}
+bool
+Debugger::GetEscapeNonPrintables () const
+{
+ const uint32_t idx = ePropertyEscapeNonPrintables;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true);
}
#pragma mark Debugger
@@ -620,24 +646,25 @@ Debugger::FindTargetWithProcess (Process *process)
return target_sp;
}
-Debugger::Debugger (lldb::LogOutputCallback log_callback, void *baton) :
- UserID (g_unique_id++),
- Properties(OptionValuePropertiesSP(new OptionValueProperties())),
- m_input_file_sp (new StreamFile (stdin, false)),
- m_output_file_sp (new StreamFile (stdout, false)),
- m_error_file_sp (new StreamFile (stderr, false)),
- m_terminal_state (),
- m_target_list (*this),
- m_platform_list (),
- m_listener ("lldb.Debugger"),
+Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) :
+ UserID(g_unique_id++),
+ Properties(OptionValuePropertiesSP(new OptionValueProperties())),
+ m_input_file_sp(new StreamFile(stdin, false)),
+ m_output_file_sp(new StreamFile(stdout, false)),
+ m_error_file_sp(new StreamFile(stderr, false)),
+ m_terminal_state(),
+ m_target_list(*this),
+ m_platform_list(),
+ m_listener("lldb.Debugger"),
m_source_manager_ap(),
m_source_file_cache(),
- m_command_interpreter_ap (new CommandInterpreter (*this, eScriptLanguageDefault, false)),
- m_input_reader_stack (),
- m_instance_name (),
- m_loaded_plugins (),
- m_event_handler_thread (LLDB_INVALID_HOST_THREAD),
- m_io_handler_thread (LLDB_INVALID_HOST_THREAD)
+ m_command_interpreter_ap(new CommandInterpreter(*this, eScriptLanguageDefault, false)),
+ m_input_reader_stack(),
+ m_instance_name(),
+ m_loaded_plugins(),
+ m_event_handler_thread (),
+ m_io_handler_thread (),
+ m_sync_broadcaster (NULL, "lldb.debugger.sync")
{
char instance_cstr[256];
snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID());
@@ -646,7 +673,7 @@ Debugger::Debugger (lldb::LogOutputCallback log_callback, void *baton) :
m_log_callback_stream_sp.reset (new StreamCallback (log_callback, baton));
m_command_interpreter_ap->Initialize ();
// Always add our default platform to the platform list
- PlatformSP default_platform_sp (Platform::GetDefaultPlatform());
+ PlatformSP default_platform_sp (Platform::GetHostPlatform());
assert (default_platform_sp.get());
m_platform_list.Append (default_platform_sp, true);
@@ -903,7 +930,6 @@ Debugger::GetTopIOHandlerControlSequence(char ch)
void
Debugger::RunIOHandler (const IOHandlerSP& reader_sp)
{
- Mutex::Locker locker (m_input_reader_stack.GetMutex());
PushIOHandler (reader_sp);
IOHandlerSP top_reader_sp = reader_sp;
@@ -1129,6 +1155,8 @@ TestPromptFormats (StackFrame *frame)
StreamString s;
const char *prompt_format =
"{addr = '${addr}'\n}"
+ "{addr-file-or-load = '${addr-file-or-load}'\n}"
+ "{current-pc-arrow = '${current-pc-arrow}'\n}"
"{process.id = '${process.id}'\n}"
"{process.name = '${process.name}'\n}"
"{process.file.basename = '${process.file.basename}'\n}"
@@ -1156,9 +1184,13 @@ TestPromptFormats (StackFrame *frame)
"{frame.reg.xmm0 = '${frame.reg.xmm0}'\n}"
"{frame.reg.carp = '${frame.reg.carp}'\n}"
"{function.id = '${function.id}'\n}"
+ "{function.changed = '${function.changed}'\n}"
+ "{function.initial-function = '${function.initial-function}'\n}"
"{function.name = '${function.name}'\n}"
+ "{function.name-without-args = '${function.name-without-args}'\n}"
"{function.name-with-args = '${function.name-with-args}'\n}"
"{function.addr-offset = '${function.addr-offset}'\n}"
+ "{function.concrete-only-addr-offset-no-padding = '${function.concrete-only-addr-offset-no-padding}'\n}"
"{function.line-offset = '${function.line-offset}'\n}"
"{function.pc-offset = '${function.pc-offset}'\n}"
"{line.file.basename = '${line.file.basename}'\n}"
@@ -1556,7 +1588,9 @@ FormatPromptRecurse
const Address *addr,
Stream &s,
const char **end,
- ValueObject* valobj
+ ValueObject* valobj,
+ bool function_changed,
+ bool initial_function
)
{
ValueObject* realvalobj = NULL; // makes it super-easy to parse pointers
@@ -1598,7 +1632,7 @@ FormatPromptRecurse
++p; // Skip the '{'
- if (FormatPromptRecurse (p, sc, exe_ctx, addr, sub_strm, &p, valobj))
+ if (FormatPromptRecurse (p, sc, exe_ctx, addr, sub_strm, &p, valobj, function_changed, initial_function))
{
// The stream had all it needed
s.Write(sub_strm.GetData(), sub_strm.GetSize());
@@ -1632,6 +1666,12 @@ FormatPromptRecurse
const char *cstr = NULL;
std::string token_format;
Address format_addr;
+
+ // normally "addr" means print a raw address but
+ // "file-addr-or-load-addr" means print a module + file addr if there's no load addr
+ bool print_file_addr_or_load_addr = false;
+ bool addr_offset_concrete_func_only = false;
+ bool addr_offset_print_with_no_padding = false;
bool calculate_format_addr_function_offset = false;
// Set reg_kind and reg_num to invalid values
RegisterKind reg_kind = kNumRegisterKinds;
@@ -1710,6 +1750,15 @@ FormatPromptRecurse
target = valobj;
val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
}
+ else if (IsToken (var_name_begin, "var.script:"))
+ {
+ var_name_begin += ::strlen("var.script:");
+ std::string script_name(var_name_begin,var_name_end);
+ ScriptInterpreter* script_interpreter = valobj->GetTargetSP()->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (RunScriptFormatKeyword (s, script_interpreter, valobj, script_name))
+ var_success = true;
+ break;
+ }
else if (IsToken (var_name_begin,"var%"))
{
was_var_format = true;
@@ -1778,6 +1827,7 @@ FormatPromptRecurse
log->Printf("[Debugger::FormatPrompt] ALL RIGHT: unparsed portion = %s, why stopping = %d,"
" final_value_type %d",
first_unparsed, reason_to_stop, final_value_type);
+ target = target->GetQualifiedRepresentationIfAvailable(target->GetDynamicValueType(), true).get();
}
}
else
@@ -1826,8 +1876,8 @@ FormatPromptRecurse
// TODO use flags for these
const uint32_t type_info_flags = target->GetClangType().GetTypeInfo(NULL);
- bool is_array = (type_info_flags & ClangASTType::eTypeIsArray) != 0;
- bool is_pointer = (type_info_flags & ClangASTType::eTypeIsPointer) != 0;
+ bool is_array = (type_info_flags & eTypeIsArray) != 0;
+ bool is_pointer = (type_info_flags & eTypeIsPointer) != 0;
bool is_aggregate = target->GetClangType().IsAggregateType();
if ((is_array || is_pointer) && (!is_array_range) && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) // this should be wrong, but there are some exceptions
@@ -1942,7 +1992,7 @@ FormatPromptRecurse
if (!special_directions)
var_success &= item->DumpPrintableRepresentation(s,val_obj_display, custom_format);
else
- var_success &= FormatPromptRecurse(special_directions, sc, exe_ctx, addr, s, NULL, item);
+ var_success &= FormatPromptRecurse(special_directions, sc, exe_ctx, addr, s, NULL, item, function_changed, initial_function);
if (--max_num_children == 0)
{
@@ -1958,7 +2008,12 @@ FormatPromptRecurse
}
break;
case 'a':
- if (IsToken (var_name_begin, "addr}"))
+ if (IsToken (var_name_begin, "addr-file-or-load}"))
+ {
+ print_file_addr_or_load_addr = true;
+ }
+ if (IsToken (var_name_begin, "addr}")
+ || IsToken (var_name_begin, "addr-file-or-load}"))
{
if (addr && addr->IsValid())
{
@@ -2160,8 +2215,7 @@ FormatPromptRecurse
}
}
break;
-
-
+
case 'm':
if (IsToken (var_name_begin, "module."))
{
@@ -2289,6 +2343,14 @@ FormatPromptRecurse
var_success = true;
}
+ if (IsToken (var_name_begin, "changed}") && function_changed)
+ {
+ var_success = true;
+ }
+ if (IsToken (var_name_begin, "initial-function}") && initial_function)
+ {
+ var_success = true;
+ }
else if (IsToken (var_name_begin, "name}"))
{
if (sc->function)
@@ -2315,6 +2377,19 @@ FormatPromptRecurse
var_success = true;
}
}
+ else if (IsToken (var_name_begin, "name-without-args}"))
+ {
+ ConstString name;
+ if (sc->function)
+ name = sc->function->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments);
+ else if (sc->symbol)
+ name = sc->symbol->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments);
+ if (name)
+ {
+ s.PutCString(name.GetCString());
+ var_success = true;
+ }
+ }
else if (IsToken (var_name_begin, "name-with-args}"))
{
// Print the function name with arguments in it
@@ -2418,7 +2493,7 @@ FormatPromptRecurse
.SetHideItemNames(false)
.SetShowMembersOneLiner(true),
"");
- format.FormatObject(var_value_sp.get(), buffer);
+ format.FormatObject(var_value_sp.get(), buffer, TypeSummaryOptions());
var_representation = buffer.c_str();
}
else
@@ -2458,8 +2533,14 @@ FormatPromptRecurse
}
}
}
- else if (IsToken (var_name_begin, "addr-offset}"))
+ else if (IsToken (var_name_begin, "addr-offset}")
+ || IsToken (var_name_begin, "concrete-only-addr-offset-no-padding}"))
{
+ if (IsToken (var_name_begin, "concrete-only-addr-offset-no-padding}"))
+ {
+ addr_offset_print_with_no_padding = true;
+ addr_offset_concrete_func_only = true;
+ }
var_success = addr != NULL;
if (var_success)
{
@@ -2530,6 +2611,35 @@ FormatPromptRecurse
}
}
break;
+ case 'c':
+ if (IsToken (var_name_begin, "current-pc-arrow"))
+ {
+ if (addr && exe_ctx && exe_ctx->GetFramePtr())
+ {
+ RegisterContextSP reg_ctx = exe_ctx->GetFramePtr()->GetRegisterContextSP();
+ if (reg_ctx.get())
+ {
+ addr_t pc_loadaddr = reg_ctx->GetPC();
+ if (pc_loadaddr != LLDB_INVALID_ADDRESS)
+ {
+ Address pc;
+ pc.SetLoadAddress (pc_loadaddr, exe_ctx->GetTargetPtr());
+ if (pc == *addr)
+ {
+ s.Printf ("-> ");
+ var_success = true;
+ }
+ }
+ }
+ if (var_success == false)
+ {
+ s.Printf(" ");
+ var_success = true;
+ }
+ }
+ var_success = true;
+ }
+ break;
}
if (var_success)
@@ -2587,7 +2697,7 @@ FormatPromptRecurse
if (sc->function)
{
func_addr = sc->function->GetAddressRange().GetBaseAddress();
- if (sc->block)
+ if (sc->block && addr_offset_concrete_func_only == false)
{
// Check to make sure we aren't in an inline
// function. If we are, use the inline block
@@ -2605,14 +2715,19 @@ FormatPromptRecurse
if (func_addr.IsValid())
{
+ const char *addr_offset_padding = " ";
+ if (addr_offset_print_with_no_padding)
+ {
+ addr_offset_padding = "";
+ }
if (func_addr.GetSection() == format_addr.GetSection())
{
addr_t func_file_addr = func_addr.GetFileAddress();
addr_t addr_file_addr = format_addr.GetFileAddress();
if (addr_file_addr > func_file_addr)
- s.Printf(" + %" PRIu64, addr_file_addr - func_file_addr);
+ 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(" - %" PRIu64, func_file_addr - addr_file_addr);
+ s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_file_addr - addr_file_addr);
var_success = true;
}
else
@@ -2623,9 +2738,9 @@ FormatPromptRecurse
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)
- s.Printf(" + %" PRIu64, addr_load_addr - func_load_addr);
+ 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(" - %" PRIu64, func_load_addr - addr_load_addr);
+ s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_load_addr - addr_load_addr);
var_success = true;
}
}
@@ -2642,10 +2757,21 @@ FormatPromptRecurse
if (vaddr != LLDB_INVALID_ADDRESS)
{
- int addr_width = target->GetArchitecture().GetAddressByteSize() * 2;
+ int addr_width = 0;
+ if (exe_ctx && target)
+ {
+ addr_width = target->GetArchitecture().GetAddressByteSize() * 2;
+ }
if (addr_width == 0)
addr_width = 16;
- s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr);
+ if (print_file_addr_or_load_addr)
+ {
+ format_addr.Dump (&s, exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, 0);
+ }
+ else
+ {
+ s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr);
+ }
var_success = true;
}
}
@@ -2759,9 +2885,55 @@ Debugger::FormatPrompt
std::string format_str = lldb_utility::ansi::FormatAnsiTerminalCodes (format, use_color);
if (format_str.length())
format = format_str.c_str();
- return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, valobj);
+ return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, valobj, false, false);
+}
+
+bool
+Debugger::FormatDisassemblerAddress (const char *format,
+ const SymbolContext *sc,
+ const SymbolContext *prev_sc,
+ const ExecutionContext *exe_ctx,
+ const Address *addr,
+ Stream &s)
+{
+ if (format == NULL && exe_ctx != NULL && exe_ctx->HasTargetScope())
+ {
+ format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();
+ }
+ bool function_changed = false;
+ bool initial_function = false;
+ if (prev_sc && (prev_sc->function || prev_sc->symbol))
+ {
+ if (sc && (sc->function || sc->symbol))
+ {
+ if (prev_sc->symbol && sc->symbol)
+ {
+ if (!sc->symbol->Compare (prev_sc->symbol->GetName(), prev_sc->symbol->GetType()))
+ {
+ function_changed = true;
+ }
+ }
+ else if (prev_sc->function && sc->function)
+ {
+ if (prev_sc->function->GetMangled() != sc->function->GetMangled())
+ {
+ function_changed = true;
+ }
+ }
+ }
+ }
+ // The first context on a list of instructions will have a prev_sc that
+ // has no Function or Symbol -- if SymbolContext had an IsValid() method, it
+ // would return false. But we do get a prev_sc pointer.
+ if ((sc && (sc->function || sc->symbol))
+ && prev_sc && (prev_sc->function == NULL && prev_sc->symbol == NULL))
+ {
+ initial_function = true;
+ }
+ return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, NULL, function_changed, initial_function);
}
+
void
Debugger::SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton)
{
@@ -2952,6 +3124,7 @@ Debugger::GetProcessSTDERR (Process *process, Stream *stream)
return total_bytes;
}
+
// This function handles events that were broadcast by the process.
void
Debugger::HandleProcessEvent (const EventSP &event_sp)
@@ -2959,7 +3132,7 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
using namespace lldb;
const uint32_t event_type = event_sp->GetType();
ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
-
+
StreamString output_stream;
StreamString error_stream;
const bool gui_enabled = IsForwardingEvents();
@@ -2968,191 +3141,27 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
{
bool pop_process_io_handler = false;
assert (process_sp);
-
+
if (event_type & Process::eBroadcastBitSTDOUT || event_type & Process::eBroadcastBitStateChanged)
{
GetProcessSTDOUT (process_sp.get(), &output_stream);
}
-
+
if (event_type & Process::eBroadcastBitSTDERR || event_type & Process::eBroadcastBitStateChanged)
{
GetProcessSTDERR (process_sp.get(), &error_stream);
}
-
+
if (event_type & Process::eBroadcastBitStateChanged)
{
-
- // Drain all stout and stderr so we don't see any output come after
- // we print our prompts
- // Something changed in the process; get the event and report the process's current status and location to
- // the user.
- StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
- if (event_state == eStateInvalid)
- return;
-
- switch (event_state)
- {
- case eStateInvalid:
- case eStateUnloaded:
- case eStateConnected:
- case eStateAttaching:
- case eStateLaunching:
- case eStateStepping:
- case eStateDetached:
- {
- output_stream.Printf("Process %" PRIu64 " %s\n",
- process_sp->GetID(),
- StateAsCString (event_state));
-
- if (event_state == eStateDetached)
- pop_process_io_handler = true;
- }
- break;
-
- case eStateRunning:
- // Don't be chatty when we run...
- break;
-
- case eStateExited:
- process_sp->GetStatus(output_stream);
- pop_process_io_handler = true;
- break;
-
- case eStateStopped:
- case eStateCrashed:
- case eStateSuspended:
- // Make sure the program hasn't been auto-restarted:
- if (Process::ProcessEventData::GetRestartedFromEvent (event_sp.get()))
- {
- size_t num_reasons = Process::ProcessEventData::GetNumRestartedReasons(event_sp.get());
- if (num_reasons > 0)
- {
- // FIXME: Do we want to report this, or would that just be annoyingly chatty?
- if (num_reasons == 1)
- {
- const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), 0);
- output_stream.Printf("Process %" PRIu64 " stopped and restarted: %s\n",
- process_sp->GetID(),
- reason ? reason : "<UNKNOWN REASON>");
- }
- else
- {
- output_stream.Printf("Process %" PRIu64 " stopped and restarted, reasons:\n",
- process_sp->GetID());
-
-
- for (size_t i = 0; i < num_reasons; i++)
- {
- const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), i);
- output_stream.Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>");
- }
- }
- }
- }
- else
- {
- // Lock the thread list so it doesn't change on us, this is the scope for the locker:
- {
- ThreadList &thread_list = process_sp->GetThreadList();
- Mutex::Locker locker (thread_list.GetMutex());
-
- ThreadSP curr_thread (thread_list.GetSelectedThread());
- ThreadSP thread;
- StopReason curr_thread_stop_reason = eStopReasonInvalid;
- if (curr_thread)
- curr_thread_stop_reason = curr_thread->GetStopReason();
- if (!curr_thread ||
- !curr_thread->IsValid() ||
- curr_thread_stop_reason == eStopReasonInvalid ||
- curr_thread_stop_reason == eStopReasonNone)
- {
- // Prefer a thread that has just completed its plan over another thread as current thread.
- ThreadSP plan_thread;
- ThreadSP other_thread;
- const size_t num_threads = thread_list.GetSize();
- size_t i;
- for (i = 0; i < num_threads; ++i)
- {
- thread = thread_list.GetThreadAtIndex(i);
- StopReason thread_stop_reason = thread->GetStopReason();
- switch (thread_stop_reason)
- {
- case eStopReasonInvalid:
- case eStopReasonNone:
- break;
-
- case eStopReasonTrace:
- case eStopReasonBreakpoint:
- case eStopReasonWatchpoint:
- case eStopReasonSignal:
- case eStopReasonException:
- case eStopReasonExec:
- case eStopReasonThreadExiting:
- if (!other_thread)
- other_thread = thread;
- break;
- case eStopReasonPlanComplete:
- if (!plan_thread)
- plan_thread = thread;
- break;
- }
- }
- if (plan_thread)
- thread_list.SetSelectedThreadByID (plan_thread->GetID());
- else if (other_thread)
- thread_list.SetSelectedThreadByID (other_thread->GetID());
- else
- {
- if (curr_thread && curr_thread->IsValid())
- thread = curr_thread;
- else
- thread = thread_list.GetThreadAtIndex(0);
-
- if (thread)
- thread_list.SetSelectedThreadByID (thread->GetID());
- }
- }
- }
- // Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code,
- // e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to
- // have a hard time restarting the process.
-
- if (GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget())
- {
- const bool only_threads_with_stop_reason = true;
- const uint32_t start_frame = 0;
- const uint32_t num_frames = 1;
- const uint32_t num_frames_with_source = 1;
- process_sp->GetStatus(output_stream);
- process_sp->GetThreadStatus (output_stream,
- only_threads_with_stop_reason,
- start_frame,
- num_frames,
- num_frames_with_source);
- }
- else
- {
- uint32_t target_idx = GetTargetList().GetIndexOfTarget(process_sp->GetTarget().shared_from_this());
- if (target_idx != UINT32_MAX)
- output_stream.Printf ("Target %d: (", target_idx);
- else
- output_stream.Printf ("Target <unknown index>: (");
- process_sp->GetTarget().Dump (&output_stream, eDescriptionLevelBrief);
- output_stream.Printf (") stopped.\n");
- }
-
- // Pop the process IO handler
- pop_process_io_handler = true;
- }
- break;
- }
+ Process::HandleProcessStateChangedEvent (event_sp, &output_stream, pop_process_io_handler);
}
-
+
if (output_stream.GetSize() || error_stream.GetSize())
{
StreamFileSP error_stream_sp (GetOutputFile());
bool top_io_handler_hid = false;
-
+
if (process_sp->ProcessIOHandlerIsActive() == false)
top_io_handler_hid = HideTopIOHandler();
@@ -3245,17 +3254,14 @@ Debugger::DefaultEventHandler()
CommandInterpreter::eBroadcastBitQuitCommandReceived |
CommandInterpreter::eBroadcastBitAsynchronousOutputData |
CommandInterpreter::eBroadcastBitAsynchronousErrorData );
-
+
+ // Let the thread that spawned us know that we have started up and
+ // that we are now listening to all required events so no events get missed
+ m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening);
+
bool done = false;
while (!done)
{
-// Mutex::Locker locker;
-// if (locker.TryLock(m_input_reader_stack.GetMutex()))
-// {
-// if (m_input_reader_stack.IsEmpty())
-// break;
-// }
-//
EventSP event_sp;
if (listener.WaitForEvent(NULL, event_sp))
{
@@ -3337,19 +3343,38 @@ Debugger::EventHandlerThread (lldb::thread_arg_t arg)
bool
Debugger::StartEventHandlerThread()
{
- if (!IS_VALID_LLDB_HOST_THREAD(m_event_handler_thread))
- m_event_handler_thread = Host::ThreadCreate("lldb.debugger.event-handler", EventHandlerThread, this, NULL);
- return IS_VALID_LLDB_HOST_THREAD(m_event_handler_thread);
+ if (!m_event_handler_thread.IsJoinable())
+ {
+ // We must synchronize with the DefaultEventHandler() thread to ensure
+ // it is up and running and listening to events before we return from
+ // this function. We do this by listening to events for the
+ // eBroadcastBitEventThreadIsListening from the m_sync_broadcaster
+ Listener listener("lldb.debugger.event-handler");
+ listener.StartListeningForEvents(&m_sync_broadcaster, eBroadcastBitEventThreadIsListening);
+
+ // Use larger 8MB stack for this thread
+ m_event_handler_thread = ThreadLauncher::LaunchThread("lldb.debugger.event-handler", EventHandlerThread,
+ this,
+ NULL,
+ g_debugger_event_thread_stack_bytes);
+
+ // Make sure DefaultEventHandler() is running and listening to events before we return
+ // from this function. We are only listening for events of type
+ // eBroadcastBitEventThreadIsListening so we don't need to check the event, we just need
+ // to wait an infinite amount of time for it (NULL timeout as the first parameter)
+ lldb::EventSP event_sp;
+ listener.WaitForEvent(NULL, event_sp);
+ }
+ return m_event_handler_thread.IsJoinable();
}
void
Debugger::StopEventHandlerThread()
{
- if (IS_VALID_LLDB_HOST_THREAD(m_event_handler_thread))
+ if (m_event_handler_thread.IsJoinable())
{
GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived);
- Host::ThreadJoin(m_event_handler_thread, NULL, NULL);
- m_event_handler_thread = LLDB_INVALID_HOST_THREAD;
+ m_event_handler_thread.Join(nullptr);
}
}
@@ -3366,21 +3391,43 @@ Debugger::IOHandlerThread (lldb::thread_arg_t arg)
bool
Debugger::StartIOHandlerThread()
{
- if (!IS_VALID_LLDB_HOST_THREAD(m_io_handler_thread))
- m_io_handler_thread = Host::ThreadCreate("lldb.debugger.io-handler", IOHandlerThread, this, NULL);
- return IS_VALID_LLDB_HOST_THREAD(m_io_handler_thread);
+ if (!m_io_handler_thread.IsJoinable())
+ m_io_handler_thread = ThreadLauncher::LaunchThread ("lldb.debugger.io-handler",
+ IOHandlerThread,
+ this,
+ NULL,
+ 8*1024*1024); // Use larger 8MB stack for this thread
+ return m_io_handler_thread.IsJoinable();
}
void
Debugger::StopIOHandlerThread()
{
- if (IS_VALID_LLDB_HOST_THREAD(m_io_handler_thread))
+ if (m_io_handler_thread.IsJoinable())
{
if (m_input_file_sp)
m_input_file_sp->GetFile().Close();
- Host::ThreadJoin(m_io_handler_thread, NULL, NULL);
- m_io_handler_thread = LLDB_INVALID_HOST_THREAD;
+ m_io_handler_thread.Join(nullptr);
}
}
+Target *
+Debugger::GetDummyTarget()
+{
+ return m_target_list.GetDummyTarget (*this).get();
+}
+
+Target *
+Debugger::GetSelectedOrDummyTarget(bool prefer_dummy)
+{
+ Target *target = nullptr;
+ if (!prefer_dummy)
+ {
+ target = m_target_list.GetSelectedTarget().get();
+ if (target)
+ return target;
+ }
+
+ return GetDummyTarget();
+}
diff --git a/source/Core/Disassembler.cpp b/source/Core/Disassembler.cpp
index 1d2b8cf04c32..649f0c5bcb26 100644
--- a/source/Core/Disassembler.cpp
+++ b/source/Core/Disassembler.cpp
@@ -410,17 +410,18 @@ Disassembler::PrintInstructions
SymbolContext prev_sc;
AddressRange sc_range;
const Address *pc_addr_ptr = NULL;
- ExecutionContextScope *exe_scope = exe_ctx.GetBestExecutionContextScope();
StackFrame *frame = exe_ctx.GetFramePtr();
TargetSP target_sp (exe_ctx.GetTargetSP());
SourceManager &source_manager = target_sp ? target_sp->GetSourceManager() : debugger.GetSourceManager();
if (frame)
+ {
pc_addr_ptr = &frame->GetFrameCodeAddress();
+ }
const uint32_t scope = eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;
const bool use_inline_block_range = false;
- for (size_t i=0; i<num_instructions_found; ++i)
+ for (size_t i = 0; i < num_instructions_found; ++i)
{
Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get();
if (inst)
@@ -447,7 +448,7 @@ Disassembler::PrintInstructions
if (offset != 0)
strm.EOL();
- sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false);
+ sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false, false);
strm.EOL();
if (sc.comp_unit && sc.line_entry.IsValid())
@@ -462,23 +463,6 @@ Disassembler::PrintInstructions
}
}
}
- else if ((sc.function || sc.symbol) && (sc.function != prev_sc.function || sc.symbol != prev_sc.symbol))
- {
- if (prev_sc.function || prev_sc.symbol)
- strm.EOL();
-
- bool show_fullpaths = false;
- bool show_module = true;
- bool show_inlined_frames = true;
- sc.DumpStopContext (&strm,
- exe_scope,
- addr,
- show_fullpaths,
- show_module,
- show_inlined_frames);
-
- strm << ":\n";
- }
}
else
{
@@ -486,12 +470,13 @@ Disassembler::PrintInstructions
}
}
- if ((options & eOptionMarkPCAddress) && pc_addr_ptr)
+ const bool show_bytes = (options & eOptionShowBytes) != 0;
+ const char *disassembly_format = "${addr-file-or-load}: ";
+ if (exe_ctx.HasTargetScope())
{
- strm.PutCString(inst_is_at_pc ? "-> " : " ");
+ disassembly_format = exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat ();
}
- const bool show_bytes = (options & eOptionShowBytes) != 0;
- inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx);
+ inst->Dump (&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, disassembly_format);
strm.EOL();
}
else
@@ -578,7 +563,10 @@ Instruction::Dump (lldb_private::Stream *s,
uint32_t max_opcode_byte_size,
bool show_address,
bool show_bytes,
- const ExecutionContext* exe_ctx)
+ const ExecutionContext* exe_ctx,
+ const SymbolContext *sym_ctx,
+ const SymbolContext *prev_sym_ctx,
+ const char *disassembly_addr_format_spec)
{
size_t opcode_column_width = 7;
const size_t operand_column_width = 25;
@@ -589,13 +577,7 @@ Instruction::Dump (lldb_private::Stream *s,
if (show_address)
{
- m_address.Dump(&ss,
- exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL,
- Address::DumpStyleLoadAddress,
- Address::DumpStyleModuleWithFileAddress,
- 0);
-
- ss.PutCString(": ");
+ Debugger::FormatDisassemblerAddress (disassembly_addr_format_spec, sym_ctx, prev_sym_ctx, exe_ctx, &m_address, ss);
}
if (show_bytes)
@@ -621,7 +603,7 @@ Instruction::Dump (lldb_private::Stream *s,
}
}
- const size_t opcode_pos = ss.GetSize();
+ const size_t opcode_pos = ss.GetSizeOfLastLine();
// The default opcode size of 7 characters is plenty for most architectures
// but some like arm can pull out the occasional vqrshrun.s16. We won't get
@@ -1003,13 +985,18 @@ InstructionList::Dump (Stream *s,
{
const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
collection::const_iterator pos, begin, end;
+ const char *disassemble_format = "${addr-file-or-load}: ";
+ if (exe_ctx)
+ {
+ disassemble_format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat ();
+ }
for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin;
pos != end;
++pos)
{
if (pos != begin)
s->EOL();
- (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx);
+ (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, NULL, NULL, disassemble_format);
}
}
diff --git a/source/Core/FastDemangle.cpp b/source/Core/FastDemangle.cpp
index 00a75425b689..53e8972e8048 100644
--- a/source/Core/FastDemangle.cpp
+++ b/source/Core/FastDemangle.cpp
@@ -18,7 +18,7 @@
//#define DEBUG_REORDERING 1
namespace {
-
+
/// @brief Represents the collection of qualifiers on a type
enum Qualifiers
@@ -51,7 +51,7 @@ enum class OperatorKind
struct Operator
{
- const char * name;
+ const char *name;
OperatorKind kind;
};
@@ -87,28 +87,28 @@ struct NameState
class SymbolDemangler
{
public:
-
+
//----------------------------------------------------
// Public API
//----------------------------------------------------
-
+
/// @brief Create a SymbolDemangler
///
/// The newly created demangler allocates and owns scratch memory sufficient
/// for demangling typical symbols. Additional memory will be allocated if
/// needed and managed by the demangler instance.
-
+
SymbolDemangler()
{
- buffer = (char *) malloc(8192);
- buffer_end = buffer + 8192;
- owns_buffer = true;
-
- rewrite_ranges = (BufferRange *) malloc(128 * sizeof(BufferRange));
- rewrite_ranges_size = 128;
- owns_rewrite_ranges = true;
+ m_buffer = (char *) malloc(8192);
+ m_buffer_end = m_buffer + 8192;
+ m_owns_buffer = true;
+
+ m_rewrite_ranges = (BufferRange *) malloc(128 * sizeof (BufferRange));
+ m_rewrite_ranges_size = 128;
+ m_owns_m_rewrite_ranges = true;
}
-
+
/// @brief Create a SymbolDemangler that uses provided scratch memory
///
/// The provided memory is not owned by the demangler. It will be
@@ -124,34 +124,36 @@ public:
///
/// @param storage_size Number of bytes of space available scratch memory
/// referenced by storage_ptr
-
- SymbolDemangler(void * storage_ptr, int storage_size)
+
+ SymbolDemangler(void *storage_ptr, int storage_size)
{
// Use up to 1/8th of the provided space for rewrite ranges
- rewrite_ranges_size = (storage_size >> 3) / sizeof(BufferRange);
- rewrite_ranges = (BufferRange *) storage_ptr;
- owns_rewrite_ranges = false;
-
+ m_rewrite_ranges_size = (storage_size >> 3) / sizeof (BufferRange);
+ m_rewrite_ranges = (BufferRange *) storage_ptr;
+ m_owns_m_rewrite_ranges = false;
+
// Use the rest for the character buffer
- buffer = (char *) storage_ptr + rewrite_ranges_size * sizeof(BufferRange);
- buffer_end = (const char *)storage_ptr + storage_size;
- owns_buffer = false;
+ m_buffer = (char *) storage_ptr + m_rewrite_ranges_size * sizeof (BufferRange);
+ m_buffer_end = (const char *)storage_ptr + storage_size;
+ m_owns_buffer = false;
}
-
+
/// @brief Destroys the SymbolDemangler and deallocates any scratch
/// memory that it owns
-
+
~SymbolDemangler()
{
- if (owns_buffer) free(buffer);
- if (owns_rewrite_ranges) free(rewrite_ranges);
+ if (m_owns_buffer)
+ free(m_buffer);
+ if (m_owns_m_rewrite_ranges)
+ free(m_rewrite_ranges);
}
-
+
#ifdef DEBUG_HIGHWATER
int highwater_store = 0;
int highwater_buffer = 0;
#endif
-
+
/// @brief Parses the provided mangled name and returns a newly allocated
/// demangling
///
@@ -161,293 +163,334 @@ public:
/// @result Newly allocated null-terminated demangled name when demangling
/// is succesful, and nullptr when demangling fails. The caller is
/// responsible for freeing the allocated memory.
-
- char * GetDemangledCopy(const char * mangled_name,
- long mangled_name_length = 0)
+
+ char *
+ GetDemangledCopy(const char *mangled_name,
+ long mangled_name_length = 0)
{
- if (!ParseMangling(mangled_name, mangled_name_length)) return nullptr;
-
+ if (!ParseMangling(mangled_name, mangled_name_length))
+ return nullptr;
+
#ifdef DEBUG_HIGHWATER
- int rewrite_count = next_substitute_index +
- (rewrite_ranges_size - 1 - next_template_arg_index);
- int buffer_size = (int)(write_ptr - buffer);
- if (rewrite_count > highwater_store) highwater_store = rewrite_count;
- if (buffer_size > highwater_buffer) highwater_buffer = buffer_size;
+ int rewrite_count = m_next_substitute_index +
+ (m_rewrite_ranges_size - 1 - m_next_template_arg_index);
+ int buffer_size = (int)(m_write_ptr - m_buffer);
+ if (rewrite_count > highwater_store)
+ highwater_store = rewrite_count;
+ if (buffer_size > highwater_buffer)
+ highwater_buffer = buffer_size;
#endif
-
- int length = (int)(write_ptr - buffer);
- char * copy = (char *)malloc(length + 1);
- memcpy(copy, buffer, length);
+
+ int length = (int)(m_write_ptr - m_buffer);
+ char *copy = (char *)malloc(length + 1);
+ memcpy(copy, m_buffer, length);
copy[length] = '\0';
return copy;
}
-
+
private:
-
+
//----------------------------------------------------
// Grow methods
//
// Manage the storage used during demangling
//----------------------------------------------------
-
+
void GrowBuffer(long min_growth = 0)
{
// By default, double the size of the buffer
- long growth = buffer_end - buffer;
-
+ long growth = m_buffer_end - m_buffer;
+
// Avoid growing by more than 1MB at a time
- if (growth > 1 << 20) growth = 1 << 20;
-
+ if (growth > 1 << 20)
+ growth = 1 << 20;
+
// ... but never grow by less than requested,
// or 1K, whichever is greater
- if (min_growth < 1024) min_growth = 1024;
- if (growth < min_growth) growth = min_growth;
-
- // Allocate the new buffer and migrate content
- long new_size = (buffer_end - buffer) + growth;
- char * new_buffer = (char *)malloc(new_size);
- memcpy(new_buffer, buffer, write_ptr - buffer);
- if (owns_buffer) free(buffer);
- owns_buffer = true;
-
+ if (min_growth < 1024)
+ min_growth = 1024;
+ if (growth < min_growth)
+ growth = min_growth;
+
+ // Allocate the new m_buffer and migrate content
+ long new_size = (m_buffer_end - m_buffer) + growth;
+ char *new_buffer = (char *) malloc(new_size);
+ memcpy(new_buffer, m_buffer, m_write_ptr - m_buffer);
+ if (m_owns_buffer)
+ free(m_buffer);
+ m_owns_buffer = true;
+
// Update references to the new buffer
- write_ptr = new_buffer + (write_ptr - buffer);
- buffer = new_buffer;
- buffer_end = buffer + new_size;
+ m_write_ptr = new_buffer + (m_write_ptr - m_buffer);
+ m_buffer = new_buffer;
+ m_buffer_end = m_buffer + new_size;
}
-
- void GrowRewriteRanges()
+
+ void
+ GrowRewriteRanges()
{
// By default, double the size of the array
- int growth = rewrite_ranges_size;
-
+ int growth = m_rewrite_ranges_size;
+
// Apply reasonable minimum and maximum sizes for growth
- if (growth > 128) growth = 128;
- if (growth < 16) growth = 16;
-
+ if (growth > 128)
+ growth = 128;
+ if (growth < 16)
+ growth = 16;
+
// Allocate the new array and migrate content
- int bytes = (rewrite_ranges_size + growth) * sizeof(BufferRange);
- BufferRange * new_ranges = (BufferRange *) malloc(bytes);
- for (int index = 0; index < next_substitute_index; index++)
+ int bytes = (m_rewrite_ranges_size + growth) * sizeof (BufferRange);
+ BufferRange *new_ranges = (BufferRange *) malloc (bytes);
+ for (int index = 0; index < m_next_substitute_index; index++)
{
- new_ranges[index] = rewrite_ranges[index];
+ new_ranges[index] = m_rewrite_ranges[index];
}
- for (int index = rewrite_ranges_size - 1;
- index > next_template_arg_index; index--)
+ for (int index = m_rewrite_ranges_size - 1;
+ index > m_next_template_arg_index; index--)
{
- new_ranges[index + growth] = rewrite_ranges[index];
+ new_ranges[index + growth] = m_rewrite_ranges[index];
}
- if (owns_rewrite_ranges) free(rewrite_ranges);
- owns_rewrite_ranges = true;
-
+ if (m_owns_m_rewrite_ranges)
+ free(m_rewrite_ranges);
+ m_owns_m_rewrite_ranges = true;
+
// Update references to the new array
- rewrite_ranges = new_ranges;
- rewrite_ranges_size += growth;
- next_template_arg_index += growth;
+ m_rewrite_ranges = new_ranges;
+ m_rewrite_ranges_size += growth;
+ m_next_template_arg_index += growth;
}
-
+
//----------------------------------------------------
// Range and state management
//----------------------------------------------------
-
- int GetStartCookie()
+
+ int
+ GetStartCookie()
{
- return (int)(write_ptr - buffer);
+ return (int)(m_write_ptr - m_buffer);
}
-
- BufferRange EndRange(int start_cookie)
+
+ BufferRange
+ EndRange(int start_cookie)
{
- return { start_cookie, (int)(write_ptr - (buffer + start_cookie)) };
+ return { start_cookie, (int)(m_write_ptr - (m_buffer + start_cookie)) };
}
-
- void ReorderRange(BufferRange source_range, int insertion_point_cookie)
+
+ void
+ ReorderRange(BufferRange source_range, int insertion_point_cookie)
{
// Ensure there's room the preserve the source range
- if (write_ptr + source_range.length > buffer_end)
+ if (m_write_ptr + source_range.length > m_buffer_end)
{
- GrowBuffer(write_ptr + source_range.length - buffer_end);
+ GrowBuffer(m_write_ptr + source_range.length - m_buffer_end);
}
-
+
// Reorder the content
- memcpy(write_ptr, buffer + source_range.offset, source_range.length);
- memmove(buffer + insertion_point_cookie + source_range.length,
- buffer + insertion_point_cookie,
+ memcpy(m_write_ptr, m_buffer + source_range.offset, source_range.length);
+ memmove(m_buffer + insertion_point_cookie + source_range.length,
+ m_buffer + insertion_point_cookie,
source_range.offset - insertion_point_cookie);
- memcpy(buffer + insertion_point_cookie, write_ptr, source_range.length);
-
+ memcpy(m_buffer + insertion_point_cookie, m_write_ptr, source_range.length);
+
// Fix up rewritable ranges, covering both substitutions and templates
int index = 0;
while (true)
{
- if (index == next_substitute_index) index = next_template_arg_index + 1;
- if (index == rewrite_ranges_size) break;
-
+ if (index == m_next_substitute_index)
+ index = m_next_template_arg_index + 1;
+ if (index == m_rewrite_ranges_size)
+ break;
+
// Affected ranges are either shuffled forward when after the
// insertion but before the source, or backward when inside the
// source
- int candidate_offset = rewrite_ranges[index].offset;
+ int candidate_offset = m_rewrite_ranges[index].offset;
if (candidate_offset >= insertion_point_cookie)
{
if (candidate_offset < source_range.offset)
{
- rewrite_ranges[index].offset += source_range.length;
+ m_rewrite_ranges[index].offset += source_range.length;
}
else if (candidate_offset >= source_range.offset)
{
- rewrite_ranges[index].offset -=
- (source_range.offset - insertion_point_cookie);
+ m_rewrite_ranges[index].offset -= (source_range.offset - insertion_point_cookie);
}
}
++index;
}
}
-
- void EndSubstitution(int start_cookie)
+
+ void
+ EndSubstitution(int start_cookie)
{
- if (next_substitute_index == next_template_arg_index) GrowRewriteRanges();
-
- int index = next_substitute_index++;
- rewrite_ranges[index] = EndRange(start_cookie);
+ if (m_next_substitute_index == m_next_template_arg_index)
+ GrowRewriteRanges();
+
+ int index = m_next_substitute_index++;
+ m_rewrite_ranges[index] = EndRange(start_cookie);
#ifdef DEBUG_SUBSTITUTIONS
printf("Saved substitution # %d = %.*s\n", index,
- rewrite_ranges[index].length, buffer + start_cookie);
+ m_rewrite_ranges[index].length, m_buffer + start_cookie);
#endif
}
-
- void EndTemplateArg(int start_cookie)
+
+ void
+ EndTemplateArg(int start_cookie)
{
- if (next_substitute_index == next_template_arg_index) GrowRewriteRanges();
-
- int index = next_template_arg_index--;
- rewrite_ranges[index] = EndRange(start_cookie);
+ if (m_next_substitute_index == m_next_template_arg_index)
+ GrowRewriteRanges();
+
+ int index = m_next_template_arg_index--;
+ m_rewrite_ranges[index] = EndRange(start_cookie);
#ifdef DEBUG_TEMPLATE_ARGS
printf("Saved template arg # %d = %.*s\n",
- rewrite_ranges_size - index - 1,
- rewrite_ranges[index].length, buffer + start_cookie);
+ m_rewrite_ranges_size - index - 1,
+ m_rewrite_ranges[index].length, m_buffer + start_cookie);
#endif
}
-
- void ResetTemplateArgs()
+
+ void
+ ResetTemplateArgs()
{
//TODO: this works, but is it the right thing to do?
// Should we push/pop somehow at the call sites?
- next_template_arg_index = rewrite_ranges_size - 1;
+ m_next_template_arg_index = m_rewrite_ranges_size - 1;
}
-
+
//----------------------------------------------------
// Write methods
//
// Appends content to the existing output buffer
//----------------------------------------------------
-
- void Write(char character)
+
+ void
+ Write(char character)
{
- if (write_ptr == buffer_end) GrowBuffer();
- *write_ptr++ = character;
+ if (m_write_ptr == m_buffer_end)
+ GrowBuffer();
+ *m_write_ptr++ = character;
}
-
- void Write(const char * content)
+
+ void
+ Write(const char *content)
{
Write(content, strlen(content));
}
-
- void Write(const char * content, long content_length)
+
+ void
+ Write(const char *content, long content_length)
{
- char * end_write_ptr = write_ptr + content_length;
- if (end_write_ptr > buffer_end)
+ char *end_m_write_ptr = m_write_ptr + content_length;
+ if (end_m_write_ptr > m_buffer_end)
{
- GrowBuffer(end_write_ptr - buffer_end);
- end_write_ptr = write_ptr + content_length;
+ GrowBuffer(end_m_write_ptr - m_buffer_end);
+ end_m_write_ptr = m_write_ptr + content_length;
}
- memcpy(write_ptr, content, content_length);
- write_ptr = end_write_ptr;
+ memcpy(m_write_ptr, content, content_length);
+ m_write_ptr = end_m_write_ptr;
}
-#define WRITE(x) Write(x, sizeof(x) - 1)
-
- void WriteTemplateStart()
+#define WRITE(x) Write(x, sizeof (x) - 1)
+
+ void
+ WriteTemplateStart()
{
Write('<');
}
-
- void WriteTemplateEnd()
+
+ void
+ WriteTemplateEnd()
{
// Put a space between terminal > characters when nesting templates
- if (write_ptr != buffer && *(write_ptr - 1) == '>') WRITE(" >");
+ if (m_write_ptr != m_buffer && *(m_write_ptr - 1) == '>')
+ WRITE(" >");
else Write('>');
}
-
- void WriteCommaSpace()
+
+ void
+ WriteCommaSpace()
{
WRITE(", ");
}
-
- void WriteNamespaceSeparator()
+
+ void
+ WriteNamespaceSeparator()
{
WRITE("::");
}
-
- void WriteStdPrefix()
+
+ void
+ WriteStdPrefix()
{
WRITE("std::");
}
-
- void WriteQualifiers(int qualifiers, bool space_before_reference = true)
- {
- if (qualifiers & QualifierPointer) Write('*');
- if (qualifiers & QualifierConst) WRITE(" const");
- if (qualifiers & QualifierVolatile) WRITE(" volatile");
- if (qualifiers & QualifierRestrict) WRITE(" restrict");
+
+ void
+ WriteQualifiers(int qualifiers, bool space_before_reference = true)
+ {
+ if (qualifiers & QualifierPointer)
+ Write('*');
+ if (qualifiers & QualifierConst)
+ WRITE(" const");
+ if (qualifiers & QualifierVolatile)
+ WRITE(" volatile");
+ if (qualifiers & QualifierRestrict)
+ WRITE(" restrict");
if (qualifiers & QualifierReference)
{
- if (space_before_reference) WRITE(" &");
+ if (space_before_reference)
+ WRITE(" &");
else Write('&');
}
if (qualifiers & QualifierRValueReference)
{
- if (space_before_reference) WRITE(" &&");
+ if (space_before_reference)
+ WRITE(" &&");
else WRITE("&&");
}
}
-
+
//----------------------------------------------------
// Rewrite methods
//
// Write another copy of content already present
// earlier in the output buffer
//----------------------------------------------------
-
- void RewriteRange(BufferRange range)
+
+ void
+ RewriteRange(BufferRange range)
{
- Write(buffer + range.offset, range.length);
+ Write(m_buffer + range.offset, range.length);
}
-
- bool RewriteSubstitution(int index)
+
+ bool
+ RewriteSubstitution(int index)
{
- if (index < 0 || index >= next_substitute_index)
+ if (index < 0 || index >= m_next_substitute_index)
{
#ifdef DEBUG_FAILURES
printf("*** Invalid substitution #%d\n", index);
#endif
return false;
}
- RewriteRange(rewrite_ranges[index]);
+ RewriteRange(m_rewrite_ranges[index]);
return true;
}
-
- bool RewriteTemplateArg(int template_index)
+
+ bool
+ RewriteTemplateArg(int template_index)
{
- int index = rewrite_ranges_size - 1 - template_index;
- if (template_index < 0 || index <= next_template_arg_index)
+ int index = m_rewrite_ranges_size - 1 - template_index;
+ if (template_index < 0 || index <= m_next_template_arg_index)
{
#ifdef DEBUG_FAILURES
printf("*** Invalid template arg reference #%d\n", template_index);
#endif
return false;
}
- RewriteRange(rewrite_ranges[index]);
+ RewriteRange(m_rewrite_ranges[index]);
return true;
}
-
+
//----------------------------------------------------
// TryParse methods
//
@@ -455,45 +498,53 @@ private:
// writing to the output buffer
//
// Values indicating failure guarantee that the pre-
- // call read_ptr is unchanged
+ // call m_read_ptr is unchanged
//----------------------------------------------------
-
- int TryParseNumber()
+
+ int
+ TryParseNumber()
{
- unsigned char digit = *read_ptr - '0';
- if (digit > 9) return -1;
-
+ unsigned char digit = *m_read_ptr - '0';
+ if (digit > 9)
+ return -1;
+
int count = digit;
while (true)
{
- digit = *++read_ptr - '0';
- if (digit > 9) break;
-
+ digit = *++m_read_ptr - '0';
+ if (digit > 9)
+ break;
+
count = count * 10 + digit;
}
return count;
}
-
- int TryParseBase36Number()
+
+ int
+ TryParseBase36Number()
{
- char digit = *read_ptr;
+ char digit = *m_read_ptr;
int count;
- if (digit >= '0' && digit <= '9') count = digit -= '0';
- else if (digit >= 'A' && digit <= 'Z') count = digit -= ('A' - 10);
+ if (digit >= '0' && digit <= '9')
+ count = digit -= '0';
+ else if (digit >= 'A' && digit <= 'Z')
+ count = digit -= ('A' - 10);
else return -1;
-
+
while (true)
{
- digit = *++read_ptr;
- if (digit >= '0' && digit <= '9') digit -= '0';
- else if (digit >= 'A' && digit <= 'Z') digit -= ('A' - 10);
+ digit = *++m_read_ptr;
+ if (digit >= '0' && digit <= '9')
+ digit -= '0';
+ else if (digit >= 'A' && digit <= 'Z')
+ digit -= ('A' - 10);
else break;
-
+
count = count * 36 + digit;
}
return count;
}
-
+
// <builtin-type> ::= v # void
// ::= w # wchar_t
// ::= b # bool
@@ -524,10 +575,11 @@ private:
// ::= Da # auto (in dependent new-expressions)
// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
// ::= u <source-name> # vendor extended type
-
- const char * TryParseBuiltinType()
+
+ const char *
+ TryParseBuiltinType()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'v': return "void";
case 'w': return "wchar_t";
@@ -552,7 +604,7 @@ private:
case 'z': return "...";
case 'D':
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'd': return "decimal64";
case 'e': return "decimal128";
@@ -564,14 +616,14 @@ private:
case 'c': return "decltype(auto)";
case 'n': return "std::nullptr_t";
default:
- --read_ptr;
+ --m_read_ptr;
}
}
}
- --read_ptr;
+ --m_read_ptr;
return nullptr;
}
-
+
// <operator-name>
// ::= aa # &&
// ::= ad # & (unary)
@@ -622,13 +674,14 @@ private:
// ::= rS # >>=
// ::= cv <type> # (cast)
// ::= v <digit> <source-name> # vendor extended operator
-
- Operator TryParseOperator()
+
+ Operator
+ TryParseOperator()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'a':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'a': return { "&&", OperatorKind::Binary };
case 'd': return { "&", OperatorKind::Unary };
@@ -636,20 +689,20 @@ private:
case 'N': return { "&=", OperatorKind::Binary };
case 'S': return { "=", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'c':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'l': return { "()", OperatorKind::Other };
case 'm': return { ",", OperatorKind::Other };
case 'o': return { "~", OperatorKind::Unary };
case 'v': return { nullptr, OperatorKind::ConversionOperator };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'd':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'a': return { " delete[]", OperatorKind::Other };
case 'e': return { "*", OperatorKind::Unary };
@@ -657,34 +710,34 @@ private:
case 'v': return { "/", OperatorKind::Binary };
case 'V': return { "/=", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'e':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'o': return { "^", OperatorKind::Binary };
case 'O': return { "^=", OperatorKind::Binary };
case 'q': return { "==", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'g':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'e': return { ">=", OperatorKind::Binary };
case 't': return { ">", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'i':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'x': return { "[]", OperatorKind::Other };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'l':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'e': return { "<=", OperatorKind::Binary };
case 's': return { "<<", OperatorKind::Binary };
@@ -692,10 +745,10 @@ private:
case 't': return { "<", OperatorKind::Binary };
// case 'i': return { "?", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'm':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'i': return { "-", OperatorKind::Binary };
case 'I': return { "-=", OperatorKind::Binary };
@@ -703,10 +756,10 @@ private:
case 'L': return { "*=", OperatorKind::Binary };
case 'm': return { "--", OperatorKind::Postfix };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'n':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'a': return { " new[]", OperatorKind::Other };
case 'e': return { "!=", OperatorKind::Binary };
@@ -714,19 +767,19 @@ private:
case 't': return { "!", OperatorKind::Unary };
case 'w': return { " new", OperatorKind::Other };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'o':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'o': return { "||", OperatorKind::Binary };
case 'r': return { "|", OperatorKind::Binary };
case 'R': return { "|=", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'p':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'm': return { "->*", OperatorKind::Binary };
case 's': return { "+", OperatorKind::Unary };
@@ -735,154 +788,161 @@ private:
case 'p': return { "++", OperatorKind::Postfix };
case 't': return { "->", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'q':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'u': return { "?", OperatorKind::Ternary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'r':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'm': return { "%", OperatorKind::Binary };
case 'M': return { "%=", OperatorKind::Binary };
case 's': return { ">>", OperatorKind::Binary };
case 'S': return { ">=", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'v':
- char digit = *read_ptr;
+ char digit = *m_read_ptr;
if (digit >= '0' && digit <= '9')
{
- read_ptr++;
+ m_read_ptr++;
return { nullptr, OperatorKind::Vendor };
}
- --read_ptr;
+ --m_read_ptr;
break;
}
- --read_ptr;
+ --m_read_ptr;
return { nullptr, OperatorKind::NoMatch };
}
-
+
// <CV-qualifiers> ::= [r] [V] [K]
// <ref-qualifier> ::= R # & ref-qualifier
// <ref-qualifier> ::= O # && ref-qualifier
-
- int TryParseQualifiers(bool allow_cv, bool allow_ro)
+
+ int
+ TryParseQualifiers(bool allow_cv, bool allow_ro)
{
int qualifiers = QualifierNone;
- char next = *read_ptr;
+ char next = *m_read_ptr;
if (allow_cv)
{
if (next == 'r') // restrict
{
qualifiers |= QualifierRestrict;
- next = *++read_ptr;
+ next = *++m_read_ptr;
}
if (next == 'V') // volatile
{
qualifiers |= QualifierVolatile;
- next = *++read_ptr;
+ next = *++m_read_ptr;
}
if (next == 'K') // const
{
qualifiers |= QualifierConst;
- next = *++read_ptr;
+ next = *++m_read_ptr;
}
}
if (allow_ro)
{
if (next == 'R')
{
- ++read_ptr;
+ ++m_read_ptr;
qualifiers |= QualifierReference;
}
else if (next =='O')
{
- ++read_ptr;
+ ++m_read_ptr;
qualifiers |= QualifierRValueReference;
}
}
return qualifiers;
}
-
+
// <discriminator> := _ <non-negative number> # when number < 10
// := __ <non-negative number> _ # when number >= 10
// extension := decimal-digit+
-
- int TryParseDiscriminator()
+
+ int
+ TryParseDiscriminator()
{
- const char * discriminator_start = read_ptr;
-
+ const char *discriminator_start = m_read_ptr;
+
// Test the extension first, since it's what Clang uses
int discriminator_value = TryParseNumber();
- if (discriminator_value != -1) return discriminator_value;
-
- char next = *read_ptr;
+ if (discriminator_value != -1)
+ return discriminator_value;
+
+ char next = *m_read_ptr;
if (next == '_')
{
- next = *++read_ptr;
+ next = *++m_read_ptr;
if (next == '_')
{
- ++read_ptr;
+ ++m_read_ptr;
discriminator_value = TryParseNumber();
- if (discriminator_value != -1 && *read_ptr++ != '_')
+ if (discriminator_value != -1 && *m_read_ptr++ != '_')
{
return discriminator_value;
}
}
else if (next >= '0' && next <= '9')
{
- ++read_ptr;
+ ++m_read_ptr;
return next - '0';
}
}
-
+
// Not a valid discriminator
- read_ptr = discriminator_start;
+ m_read_ptr = discriminator_start;
return -1;
}
-
+
//----------------------------------------------------
// Parse methods
//
- // Consume input starting from read_ptr and produce
- // buffered output at write_ptr
+ // Consume input starting from m_read_ptr and produce
+ // buffered output at m_write_ptr
//
- // Failures return false and may leave read_ptr in an
+ // Failures return false and may leave m_read_ptr in an
// indeterminate state
//----------------------------------------------------
-
- bool Parse(char character)
+
+ bool
+ Parse(char character)
{
- if (*read_ptr++ == character) return true;
+ if (*m_read_ptr++ == character)
+ return true;
#ifdef DEBUG_FAILURES
printf("*** Expected '%c'\n", character);
#endif
return false;
}
-
+
// <number> ::= [n] <non-negative decimal integer>
-
- bool ParseNumber(bool allow_negative = false)
+
+ bool
+ ParseNumber(bool allow_negative = false)
{
- if (allow_negative && *read_ptr == 'n')
+ if (allow_negative && *m_read_ptr == 'n')
{
Write('-');
- ++read_ptr;
+ ++m_read_ptr;
}
- const char * before_digits = read_ptr;
+ const char *before_digits = m_read_ptr;
while (true)
{
- unsigned char digit = *read_ptr - '0';
- if (digit > 9) break;
- ++read_ptr;
+ unsigned char digit = *m_read_ptr - '0';
+ if (digit > 9)
+ break;
+ ++m_read_ptr;
}
- if (int digit_count = (int)(read_ptr - before_digits))
+ if (int digit_count = (int)(m_read_ptr - before_digits))
{
Write(before_digits, digit_count);
return true;
@@ -892,7 +952,7 @@ private:
#endif
return false;
}
-
+
// <substitution> ::= S <seq-id> _
// ::= S_
// <substitution> ::= Sa # ::std::allocator
@@ -903,11 +963,12 @@ private:
// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
-
- bool ParseSubstitution()
+
+ bool
+ ParseSubstitution()
{
- const char * substitution;
- switch (*read_ptr)
+ const char *substitution;
+ switch (*m_read_ptr)
{
case 'a': substitution = "std::allocator"; break;
case 'b': substitution = "std::basic_string"; break;
@@ -919,25 +980,26 @@ private:
// A failed attempt to parse a number will return -1 which turns out to be
// perfect here as S_ is the first substitution, S0_ the next and so forth
int substitution_index = TryParseBase36Number();
- if (*read_ptr++ != '_')
+ if (*m_read_ptr++ != '_')
{
#ifdef DEBUG_FAILURES
printf("*** Expected terminal _ in substitution\n");
#endif
return false;
}
- return RewriteSubstitution(substitution_index + 1);
+ return RewriteSubstitution (substitution_index + 1);
}
Write(substitution);
- ++read_ptr;
+ ++m_read_ptr;
return true;
}
-
+
// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
//
// <bare-function-type> ::= <signature type>+ # types are possible return type, then parameter types
-
- bool ParseFunctionType(int inner_qualifiers = QualifierNone)
+
+ bool
+ ParseFunctionType (int inner_qualifiers = QualifierNone)
{
#ifdef DEBUG_FAILURES
printf("*** Function types not supported\n");
@@ -947,70 +1009,77 @@ private:
// int (*)() when used as the type for "name" becomes int (*name)().
// This makes substitution et al ... interesting.
return false;
-
- if (*read_ptr == 'Y') ++read_ptr;;
-
+
+#if 0 // TODO
+ if (*m_read_ptr == 'Y')
+ ++m_read_ptr;
+
int return_type_start_cookie = GetStartCookie();
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
Write(' ');
-
+
int insert_cookie = GetStartCookie();
Write('(');
bool first_param = true;
int qualifiers = QualifierNone;
while (true)
{
- switch (*read_ptr)
+ switch (*m_read_ptr)
{
case 'E':
- ++read_ptr;
+ ++m_read_ptr;
Write(')');
break;
case 'v':
- ++read_ptr;
+ ++m_read_ptr;
continue;
case 'R':
case 'O':
- if (*(read_ptr + 1) == 'E')
+ if (*(m_read_ptr + 1) == 'E')
{
- qualifiers = TryParseQualifiers(false, true);
+ qualifiers = TryParseQualifiers (false, true);
Parse('E');
break;
}
// fallthrough
default:
{
- if (first_param) first_param = false;
+ if (first_param)
+ first_param = false;
else WriteCommaSpace();
-
- if (!ParseType()) return false;
+
+ if (!ParseType())
+ return false;
continue;
}
}
break;
}
-
+
if (qualifiers)
{
- WriteQualifiers(qualifiers);
- EndSubstitution(return_type_start_cookie);
+ WriteQualifiers (qualifiers);
+ EndSubstitution (return_type_start_cookie);
}
-
+
if (inner_qualifiers)
{
int qualifier_start_cookie = GetStartCookie();
- Write('(');
- WriteQualifiers(inner_qualifiers);
- Write(')');
- ReorderRange(EndRange(qualifier_start_cookie), insert_cookie);
+ Write ('(');
+ WriteQualifiers (inner_qualifiers);
+ Write (')');
+ ReorderRange (EndRange (qualifier_start_cookie), insert_cookie);
}
return true;
+#endif // TODO
}
-
+
// <array-type> ::= A <positive dimension number> _ <element type>
// ::= A [<dimension expression>] _ <element type>
-
- bool ParseArrayType(int qualifiers = QualifierNone)
+
+ bool
+ ParseArrayType(int qualifiers = QualifierNone)
{
#ifdef DEBUG_FAILURES
printf("*** Array type unsupported\n");
@@ -1021,26 +1090,32 @@ private:
//
//TODO: Chances are we don't do any better with references and pointers
// that should be type (&) [] instead of type & []
-
+
return false;
-
- if (*read_ptr == '_')
+
+#if 0 // TODO
+ if (*m_read_ptr == '_')
{
- ++read_ptr;
- if (!ParseType()) return false;
- if (qualifiers) WriteQualifiers(qualifiers);
+ ++m_read_ptr;
+ if (!ParseType())
+ return false;
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
WRITE(" []");
return true;
}
else
{
- const char * before_digits = read_ptr;
+ const char *before_digits = m_read_ptr;
if (TryParseNumber() != -1)
{
- const char * after_digits = read_ptr;
- if (!Parse('_')) return false;
- if (!ParseType()) return false;
- if (qualifiers) WriteQualifiers(qualifiers);
+ const char *after_digits = m_read_ptr;
+ if (!Parse('_'))
+ return false;
+ if (!ParseType())
+ return false;
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
Write(' ');
Write('[');
Write(before_digits, after_digits - before_digits);
@@ -1048,51 +1123,61 @@ private:
else
{
int type_insertion_cookie = GetStartCookie();
- if (!ParseExpression()) return false;
- if (!Parse('_')) return false;
-
+ if (!ParseExpression())
+ return false;
+ if (!Parse('_'))
+ return false;
+
int type_start_cookie = GetStartCookie();
- if (!ParseType()) return false;
- if (qualifiers) WriteQualifiers(qualifiers);
+ if (!ParseType())
+ return false;
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
Write(' ');
Write('[');
- ReorderRange(EndRange(type_start_cookie), type_insertion_cookie);
+ ReorderRange (EndRange (type_start_cookie), type_insertion_cookie);
}
Write(']');
return true;
}
+#endif // TODO
}
-
+
// <pointer-to-member-type> ::= M <class type> <member type>
-
+
//TODO: Determine how to handle pointers to function members correctly,
// currently not an issue because we don't have function types at all...
- bool ParsePointerToMemberType()
+ bool
+ ParsePointerToMemberType()
{
int insertion_cookie = GetStartCookie();
Write(' ');
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
WRITE("::*");
-
+
int type_cookie = GetStartCookie();
- if (!ParseType()) return false;
- ReorderRange(EndRange(type_cookie), insertion_cookie);
+ if (!ParseType())
+ return false;
+ ReorderRange (EndRange (type_cookie), insertion_cookie);
return true;
}
-
+
// <template-param> ::= T_ # first template parameter
// ::= T <parameter-2 non-negative number> _
-
- bool ParseTemplateParam()
+
+ bool
+ ParseTemplateParam()
{
int count = TryParseNumber();
- if (!Parse('_')) return false;
-
+ if (!Parse('_'))
+ return false;
+
// When no number is present we get -1, which is convenient since
// T_ is the zeroth element T0_ is element 1, and so on
- return RewriteTemplateArg(count + 1);
+ return RewriteTemplateArg (count + 1);
}
-
+
// <type> ::= <builtin-type>
// ::= <function-type>
// ::= <class-enum-type>
@@ -1112,27 +1197,29 @@ private:
// ::= U <source-name> <type> # vendor extended type qualifier
// extension := U <objc-name> <objc-type> # objc-type<identifier>
// extension := <vector-type> # <vector-type> starts with Dv
-
+
// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
-
- bool ParseType()
+
+ bool
+ ParseType()
{
#ifdef DEBUG_FAILURES
- const char * failed_type = read_ptr;
+ const char *failed_type = m_read_ptr;
#endif
int type_start_cookie = GetStartCookie();
bool suppress_substitution = false;
-
- int qualifiers = TryParseQualifiers(true, false);
- switch (*read_ptr)
+
+ int qualifiers = TryParseQualifiers (true, false);
+ switch (*m_read_ptr)
{
case 'D':
- ++read_ptr;
- switch (*read_ptr++)
+ ++m_read_ptr;
+ switch (*m_read_ptr++)
{
case 'p':
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
break;
case 'T':
case 't':
@@ -1145,44 +1232,52 @@ private:
}
break;
case 'T':
- ++read_ptr;
- if (!ParseTemplateParam()) return false;
+ ++m_read_ptr;
+ if (!ParseTemplateParam())
+ return false;
break;
case 'M':
- ++read_ptr;
- if (!ParsePointerToMemberType()) return false;
+ ++m_read_ptr;
+ if (!ParsePointerToMemberType())
+ return false;
break;
case 'A':
- ++read_ptr;
- if (!ParseArrayType()) return false;
+ ++m_read_ptr;
+ if (!ParseArrayType())
+ return false;
break;
case 'F':
- ++read_ptr;
- if (!ParseFunctionType()) return false;
+ ++m_read_ptr;
+ if (!ParseFunctionType())
+ return false;
break;
case 'S':
- if (*++read_ptr == 't')
+ if (*++m_read_ptr == 't')
{
- ++read_ptr;
+ ++m_read_ptr;
WriteStdPrefix();
- if (!ParseName()) return false;
+ if (!ParseName())
+ return false;
}
else
{
suppress_substitution = true;
- if (!ParseSubstitution()) return false;
+ if (!ParseSubstitution())
+ return false;
}
break;
case 'P':
{
- switch (*++read_ptr)
+ switch (*++m_read_ptr)
{
case 'F':
- ++read_ptr;
- if (!ParseFunctionType(QualifierPointer)) return false;
+ ++m_read_ptr;
+ if (!ParseFunctionType(QualifierPointer))
+ return false;
break;
default:
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
Write('*');
break;
}
@@ -1190,15 +1285,17 @@ private:
}
case 'R':
{
- ++read_ptr;
- if (!ParseType()) return false;
+ ++m_read_ptr;
+ if (!ParseType())
+ return false;
Write('&');
break;
}
case 'O':
{
- ++read_ptr;
- if (!ParseType()) return false;
+ ++m_read_ptr;
+ if (!ParseType())
+ return false;
Write('&');
Write('&');
break;
@@ -1214,24 +1311,27 @@ private:
case 'N':
case 'Z':
case 'L':
- if (!ParseName()) return false;
+ if (!ParseName())
+ return false;
break;
default:
- if (const char * builtin = TryParseBuiltinType())
+ if (const char *builtin = TryParseBuiltinType())
{
Write(builtin);
suppress_substitution = true;
}
else
{
- if (!ParseName()) return false;
+ if (!ParseName())
+ return false;
}
break;
}
-
+
// Allow base substitutions to be suppressed, but always record
// substitutions for the qualified variant
- if (!suppress_substitution) EndSubstitution(type_start_cookie);
+ if (!suppress_substitution)
+ EndSubstitution(type_start_cookie);
if (qualifiers)
{
WriteQualifiers(qualifiers, false);
@@ -1239,40 +1339,43 @@ private:
}
return true;
}
-
+
// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
// ::= <closure-type-name>
//
// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
//
// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
-
- bool ParseUnnamedTypeName(NameState & name_state)
+
+ bool
+ ParseUnnamedTypeName(NameState & name_state)
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 't':
{
int cookie = GetStartCookie();
WRITE("'unnamed");
- const char * before_digits = read_ptr;
- if (TryParseNumber() != -1) Write(before_digits,
- read_ptr - before_digits);
- if (!Parse('_')) return false;
+ const char *before_digits = m_read_ptr;
+ if (TryParseNumber() != -1) Write (before_digits,
+ m_read_ptr - before_digits);
+ if (!Parse('_'))
+ return false;
Write('\'');
- name_state.last_name_range = EndRange(cookie);
+ name_state.last_name_range = EndRange (cookie);
return true;
}
case 'b':
{
int cookie = GetStartCookie();
WRITE("'block");
- const char * before_digits = read_ptr;
- if (TryParseNumber() != -1) Write(before_digits,
- read_ptr - before_digits);
- if (!Parse('_')) return false;
+ const char *before_digits = m_read_ptr;
+ if (TryParseNumber() != -1) Write (before_digits,
+ m_read_ptr - before_digits);
+ if (!Parse('_'))
+ return false;
Write('\'');
- name_state.last_name_range = EndRange(cookie);
+ name_state.last_name_range = EndRange (cookie);
return true;
}
case 'l':
@@ -1282,23 +1385,24 @@ private:
return false;
}
#ifdef DEBUG_FAILURES
- printf("*** Unknown unnamed type %.3s\n", read_ptr - 2);
+ printf("*** Unknown unnamed type %.3s\n", m_read_ptr - 2);
#endif
return false;
}
-
+
// <ctor-dtor-name> ::= C1 # complete object constructor
// ::= C2 # base object constructor
// ::= C3 # complete object allocating constructor
-
- bool ParseCtor(NameState & name_state)
+
+ bool
+ ParseCtor(NameState & name_state)
{
- char next = *read_ptr;
+ char next = *m_read_ptr;
if (next == '1' || next == '2' || next == '3' || next == '5')
{
- RewriteRange(name_state.last_name_range);
+ RewriteRange (name_state.last_name_range);
name_state.has_no_return_type = true;
- ++read_ptr;
+ ++m_read_ptr;
return true;
}
#ifdef DEBUG_FAILURES
@@ -1306,20 +1410,21 @@ private:
#endif
return false;
}
-
+
// <ctor-dtor-name> ::= D0 # deleting destructor
// ::= D1 # complete object destructor
// ::= D2 # base object destructor
-
- bool ParseDtor(NameState & name_state)
+
+ bool
+ ParseDtor(NameState & name_state)
{
- char next = *read_ptr;
+ char next = *m_read_ptr;
if (next == '0' || next == '1' || next == '2' || next == '5')
{
Write('~');
RewriteRange(name_state.last_name_range);
name_state.has_no_return_type = true;
- ++read_ptr;
+ ++m_read_ptr;
return true;
}
#ifdef DEBUG_FAILURES
@@ -1327,13 +1432,14 @@ private:
#endif
return false;
}
-
+
// See TryParseOperator()
-
- bool ParseOperatorName(NameState & name_state)
+
+ bool
+ ParseOperatorName(NameState & name_state)
{
#ifdef DEBUG_FAILURES
- const char * operator_ptr = read_ptr;
+ const char *operator_ptr = m_read_ptr;
#endif
Operator parsed_operator = TryParseOperator();
if (parsed_operator.name)
@@ -1342,7 +1448,7 @@ private:
Write(parsed_operator.name);
return true;
}
-
+
// Handle special operators
switch (parsed_operator.kind)
{
@@ -1361,10 +1467,11 @@ private:
return false;
}
}
-
+
// <source-name> ::= <positive length number> <identifier>
-
- bool ParseSourceName()
+
+ bool
+ ParseSourceName()
{
int count = TryParseNumber();
if (count == -1)
@@ -1374,43 +1481,45 @@ private:
#endif
return false;
}
-
- const char * next_read_ptr = read_ptr + count;
- if (next_read_ptr > read_end)
+
+ const char *next_m_read_ptr = m_read_ptr + count;
+ if (next_m_read_ptr > m_read_end)
{
#ifdef DEBUG_FAILURES
printf("*** Malformed source name, premature termination\n");
#endif
return false;
}
-
- if (count >= 10 && strncmp(read_ptr, "_GLOBAL__N", 10) == 0) WRITE("(anonymous namespace)");
- else Write(read_ptr, count);
-
- read_ptr = next_read_ptr;
+
+ if (count >= 10 && strncmp(m_read_ptr, "_GLOBAL__N", 10) == 0)
+ WRITE("(anonymous namespace)");
+ else Write(m_read_ptr, count);
+
+ m_read_ptr = next_m_read_ptr;
return true;
}
-
+
// <unqualified-name> ::= <operator-name>
// ::= <ctor-dtor-name>
// ::= <source-name>
// ::= <unnamed-type-name>
-
- bool ParseUnqualifiedName(NameState & name_state)
+
+ bool
+ ParseUnqualifiedName(NameState & name_state)
{
// Note that these are detected directly in ParseNestedName for
// performance rather than switching on the same options twice
- char next = *read_ptr;
+ char next = *m_read_ptr;
switch (next)
{
case 'C':
- ++read_ptr;
+ ++m_read_ptr;
return ParseCtor(name_state);
case 'D':
- ++read_ptr;
+ ++m_read_ptr;
return ParseDtor(name_state);
case 'U':
- ++read_ptr;
+ ++m_read_ptr;
return ParseUnnamedTypeName(name_state);
case '0':
case '1':
@@ -1424,7 +1533,8 @@ private:
case '9':
{
int name_start_cookie = GetStartCookie();
- if (!ParseSourceName()) return false;
+ if (!ParseSourceName())
+ return false;
name_state.last_name_range = EndRange(name_start_cookie);
return true;
}
@@ -1432,33 +1542,40 @@ private:
return ParseOperatorName(name_state);
};
}
-
+
// <unscoped-name> ::= <unqualified-name>
// ::= St <unqualified-name> # ::std::
// extension ::= StL<unqualified-name>
-
- bool ParseUnscopedName(NameState & name_state)
+
+ bool
+ ParseUnscopedName(NameState & name_state)
{
- if (*read_ptr == 'S' && *(read_ptr + 1) == 't')
+ if (*m_read_ptr == 'S' && *(m_read_ptr + 1) == 't')
{
WriteStdPrefix();
- if (*(read_ptr += 2) == 'L') ++read_ptr;
+ if (*(m_read_ptr += 2) == 'L')
+ ++m_read_ptr;
}
return ParseUnqualifiedName(name_state);
}
-
- bool ParseIntegerLiteral(const char * prefix, const char * suffix,
+
+ bool
+ ParseIntegerLiteral(const char *prefix, const char *suffix,
bool allow_negative)
{
- if (prefix) Write(prefix);
- if (!ParseNumber(allow_negative)) return false;
- if (suffix) Write(suffix);
+ if (prefix)
+ Write(prefix);
+ if (!ParseNumber(allow_negative))
+ return false;
+ if (suffix)
+ Write(suffix);
return Parse('E');
}
-
- bool ParseBooleanLiteral()
+
+ bool
+ ParseBooleanLiteral()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case '0': WRITE("false"); break;
case '1': WRITE("true"); break;
@@ -1470,17 +1587,18 @@ private:
}
return Parse('E');
}
-
+
// <expr-primary> ::= L <type> <value number> E # integer literal
// ::= L <type> <value float> E # floating literal
// ::= L <string type> E # string literal
// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
// ::= L <mangled-name> E # external name
-
- bool ParseExpressionPrimary()
+
+ bool
+ ParseExpressionPrimary()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'b': return ParseBooleanLiteral();
case 'x': return ParseIntegerLiteral(nullptr, "ll", true);
@@ -1493,12 +1611,13 @@ private:
case 'o': return ParseIntegerLiteral("(unsigned __int128)",
nullptr, false);
case '_':
- if (*read_ptr++ == 'Z')
+ if (*m_read_ptr++ == 'Z')
{
- if (!ParseEncoding()) return false;
+ if (!ParseEncoding())
+ return false;
return Parse('E');
}
- --read_ptr;
+ --m_read_ptr;
// fallthrough
case 'w':
case 'c':
@@ -1510,7 +1629,7 @@ private:
case 'd':
case 'e':
#ifdef DEBUG_FAILURES
- printf("*** Unsupported primary expression %.5s\n", read_ptr - 1);
+ printf("*** Unsupported primary expression %.5s\n", m_read_ptr - 1);
#endif
return false;
case 'T':
@@ -1521,49 +1640,55 @@ private:
#endif
return false;
default:
- --read_ptr;
+ --m_read_ptr;
Write('(');
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
Write(')');
- if (!ParseNumber()) return false;
+ if (!ParseNumber())
+ return false;
return Parse('E');
}
}
-
+
// <unresolved-type> ::= <template-param>
// ::= <decltype>
// ::= <substitution>
-
- bool ParseUnresolvedType()
+
+ bool
+ ParseUnresolvedType()
{
int type_start_cookie = GetStartCookie();
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'T':
- if (!ParseTemplateParam()) return false;
+ if (!ParseTemplateParam())
+ return false;
EndSubstitution(type_start_cookie);
return true;
case 'S':
{
- if (*read_ptr != 't') return ParseSubstitution();
-
- ++read_ptr;
+ if (*m_read_ptr != 't')
+ return ParseSubstitution();
+
+ ++m_read_ptr;
WriteStdPrefix();
NameState type_name = {};
- if (!ParseUnqualifiedName(type_name)) return false;
+ if (!ParseUnqualifiedName(type_name))
+ return false;
EndSubstitution(type_start_cookie);
return true;
-
+
}
case 'D':
default:
#ifdef DEBUG_FAILURES
- printf("*** Unsupported unqualified type: %3s\n", read_ptr - 1);
+ printf("*** Unsupported unqualified type: %3s\n", m_read_ptr - 1);
#endif
return false;
}
}
-
+
// <base-unresolved-name> ::= <simple-id> # unresolved name
// extension ::= <operator-name> # unresolved operator-function-id
// extension ::= <operator-name> <template-args> # unresolved operator template-id
@@ -1571,15 +1696,16 @@ private:
// ::= on <operator-name> <template-args> # unresolved operator template-id
// ::= dn <destructor-name> # destructor or pseudo-destructor;
// # e.g. ~X or ~X<N-1>
-
- bool ParseBaseUnresolvedName()
+
+ bool
+ ParseBaseUnresolvedName()
{
#ifdef DEBUG_FAILURES
printf("*** Base unresolved name unsupported\n");
#endif
return false;
}
-
+
// <unresolved-name>
// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
@@ -1589,22 +1715,25 @@ private:
// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
// # T::N::x /decltype(p)::N::x
// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
-
- bool ParseUnresolvedName()
+
+ bool
+ ParseUnresolvedName()
{
#ifdef DEBUG_FAILURES
printf("*** Unresolved names not supported\n");
#endif
//TODO: grammar for all of this seems unclear...
return false;
-
- if (*read_ptr == 'g' && *(read_ptr + 1) == 's')
+
+#if 0 // TODO
+ if (*m_read_ptr == 'g' && *(m_read_ptr + 1) == 's')
{
- read_ptr += 2;
+ m_read_ptr += 2;
WriteNamespaceSeparator();
}
+#endif // TODO
}
-
+
// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
// ::= <ternary operator-name> <expression> <expression> <expression>
@@ -1644,8 +1773,9 @@ private:
// # freestanding dependent name (e.g., T::x),
// # objectless nonstatic member reference
// ::= <expr-primary>
-
- bool ParseExpression()
+
+ bool
+ ParseExpression()
{
Operator expression_operator = TryParseOperator();
switch (expression_operator.kind)
@@ -1653,17 +1783,21 @@ private:
case OperatorKind::Unary:
Write(expression_operator.name);
Write('(');
- if (!ParseExpression()) return false;
+ if (!ParseExpression())
+ return false;
Write(')');
return true;
case OperatorKind::Binary:
- if (!ParseExpression()) return false;
+ if (!ParseExpression())
+ return false;
Write(expression_operator.name);
return ParseExpression();
case OperatorKind::Ternary:
- if (!ParseExpression()) return false;
+ if (!ParseExpression())
+ return false;
Write('?');
- if (!ParseExpression()) return false;
+ if (!ParseExpression())
+ return false;
Write(':');
return ParseExpression();
case OperatorKind::NoMatch:
@@ -1675,67 +1809,75 @@ private:
#endif
return false;
}
-
- switch (*read_ptr++)
+
+ switch (*m_read_ptr++)
{
case 'T': return ParseTemplateParam();
case 'L': return ParseExpressionPrimary();
case 's':
- if (*read_ptr++ == 'r') return ParseUnresolvedName();
- --read_ptr;
+ if (*m_read_ptr++ == 'r')
+ return ParseUnresolvedName();
+ --m_read_ptr;
// fallthrough
default:
return ParseExpressionPrimary();
}
}
-
+
// <template-arg> ::= <type> # type or template
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
// ::= J <template-arg>* E # argument pack
// ::= LZ <encoding> E # extension
-
- bool ParseTemplateArg()
+
+ bool
+ ParseTemplateArg()
{
- switch (*read_ptr) {
+ switch (*m_read_ptr) {
case 'J':
#ifdef DEBUG_FAILURES
printf("*** Template argument packs unsupported\n");
#endif
return false;
case 'X':
- ++read_ptr;
- if (!ParseExpression()) return false;
+ ++m_read_ptr;
+ if (!ParseExpression())
+ return false;
return Parse('E');
case 'L':
- ++read_ptr;
+ ++m_read_ptr;
return ParseExpressionPrimary();
default:
return ParseType();
}
}
-
+
// <template-args> ::= I <template-arg>* E
// extension, the abi says <template-arg>+
-
- bool ParseTemplateArgs(bool record_template_args = false)
+
+ bool
+ ParseTemplateArgs(bool record_template_args = false)
{
- if (record_template_args) ResetTemplateArgs();
-
+ if (record_template_args)
+ ResetTemplateArgs();
+
bool first_arg = true;
- while (*read_ptr != 'E')
+ while (*m_read_ptr != 'E')
{
- if (first_arg) first_arg = false;
+ if (first_arg)
+ first_arg = false;
else WriteCommaSpace();
-
+
int template_start_cookie = GetStartCookie();
- if (!ParseTemplateArg()) return false;
- if (record_template_args) EndTemplateArg(template_start_cookie);
+ if (!ParseTemplateArg())
+ return false;
+ if (record_template_args)
+ EndTemplateArg(template_start_cookie);
}
- ++read_ptr;
+ ++m_read_ptr;
return true;
}
-
+
// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
//
@@ -1756,8 +1898,9 @@ private:
// ::= <ctor-dtor-name>
// ::= <source-name>
// ::= <unnamed-type-name>
-
- bool ParseNestedName(NameState & name_state, bool parse_discriminator = false)
+
+ bool
+ ParseNestedName(NameState & name_state, bool parse_discriminator = false)
{
int qualifiers = TryParseQualifiers(true, true);
bool first_part = true;
@@ -1765,30 +1908,33 @@ private:
int name_start_cookie = GetStartCookie();
while (true)
{
- char next = *read_ptr;
+ char next = *m_read_ptr;
if (next == 'E')
{
- ++read_ptr;
+ ++m_read_ptr;
break;
}
-
+
// Record a substitution candidate for all prefixes, but not the full name
- if (suppress_substitution) suppress_substitution = false;
+ if (suppress_substitution)
+ suppress_substitution = false;
else EndSubstitution(name_start_cookie);
-
+
if (next == 'I')
{
- ++read_ptr;
+ ++m_read_ptr;
name_state.is_last_generic = true;
WriteTemplateStart();
- if (!ParseTemplateArgs(name_state.parse_function_params)) return false;
+ if (!ParseTemplateArgs(name_state.parse_function_params))
+ return false;
WriteTemplateEnd();
continue;
}
-
- if (first_part) first_part = false;
+
+ if (first_part)
+ first_part = false;
else WriteNamespaceSeparator();
-
+
name_state.is_last_generic = false;
switch (next)
{
@@ -1804,34 +1950,39 @@ private:
case '9':
{
int name_start_cookie = GetStartCookie();
- if (!ParseSourceName()) return false;
+ if (!ParseSourceName())
+ return false;
name_state.last_name_range = EndRange(name_start_cookie);
continue;
}
case 'S':
- if (*++read_ptr == 't')
+ if (*++m_read_ptr == 't')
{
WriteStdPrefix();
- ++read_ptr;
- if (!ParseUnqualifiedName(name_state)) return false;
+ ++m_read_ptr;
+ if (!ParseUnqualifiedName(name_state))
+ return false;
}
else
{
- if (!ParseSubstitution()) return false;
+ if (!ParseSubstitution())
+ return false;
suppress_substitution = true;
}
continue;
case 'T':
- ++read_ptr;
- if (!ParseTemplateParam()) return false;
+ ++m_read_ptr;
+ if (!ParseTemplateParam())
+ return false;
continue;
case 'C':
- ++read_ptr;
- if (!ParseCtor(name_state)) return false;
+ ++m_read_ptr;
+ if (!ParseCtor(name_state))
+ return false;
continue;
case 'D':
{
- switch (*(read_ptr + 1))
+ switch (*(m_read_ptr + 1))
{
case 't':
case 'T':
@@ -1840,109 +1991,135 @@ private:
#endif
return false;
}
- ++read_ptr;
- if (!ParseDtor(name_state)) return false;
+ ++m_read_ptr;
+ if (!ParseDtor(name_state))
+ return false;
continue;
}
case 'U':
- ++read_ptr;
- if (!ParseUnnamedTypeName(name_state)) return false;
+ ++m_read_ptr;
+ if (!ParseUnnamedTypeName(name_state))
+ return false;
continue;
case 'L':
- ++read_ptr;
- if (!ParseUnqualifiedName(name_state)) return false;
+ ++m_read_ptr;
+ if (!ParseUnqualifiedName(name_state))
+ return false;
continue;
default:
- if (!ParseOperatorName(name_state)) return false;
+ if (!ParseOperatorName(name_state))
+ return false;
}
}
-
- if (parse_discriminator) TryParseDiscriminator();
- if (name_state.parse_function_params &&
- !ParseFunctionArgs(name_state, name_start_cookie)) return false;
- if (qualifiers) WriteQualifiers(qualifiers);
+
+ if (parse_discriminator)
+ TryParseDiscriminator();
+ if (name_state.parse_function_params
+ && !ParseFunctionArgs(name_state, name_start_cookie))
+ {
+ return false;
+ }
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
return true;
}
-
+
// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
// := Z <function encoding> E s [<discriminator>]
// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
-
- bool ParseLocalName(bool parse_function_params)
+
+ bool
+ ParseLocalName(bool parse_function_params)
{
- if (!ParseEncoding()) return false;
- if (!Parse('E')) return false;
-
- switch (*read_ptr)
+ if (!ParseEncoding())
+ return false;
+ if (!Parse('E'))
+ return false;
+
+ switch (*m_read_ptr)
{
case 's':
+ ++m_read_ptr;
TryParseDiscriminator(); // Optional and ignored
WRITE("::string literal");
break;
case 'd':
+ ++m_read_ptr;
TryParseNumber(); // Optional and ignored
+ if (!Parse('_'))
+ return false;
WriteNamespaceSeparator();
- if (!ParseName()) return false;
+ if (!ParseName())
+ return false;
break;
default:
WriteNamespaceSeparator();
- if (!ParseName(parse_function_params, true)) return false;
+ if (!ParseName(parse_function_params, true))
+ return false;
TryParseDiscriminator(); // Optional and ignored
}
return true;
}
-
+
// <name> ::= <nested-name>
// ::= <local-name>
// ::= <unscoped-template-name> <template-args>
// ::= <unscoped-name>
-
+
// <unscoped-template-name> ::= <unscoped-name>
// ::= <substitution>
-
- bool ParseName(bool parse_function_params = false,
+
+ bool
+ ParseName(bool parse_function_params = false,
bool parse_discriminator = false)
{
- NameState name_state = { parse_function_params };
+ NameState name_state = { parse_function_params, false, false, {0, 0}};
int name_start_cookie = GetStartCookie();
-
- switch (*read_ptr)
+
+ switch (*m_read_ptr)
{
case 'N':
- ++read_ptr;
+ ++m_read_ptr;
return ParseNestedName(name_state, parse_discriminator);
case 'Z':
{
- ++read_ptr;
- if (!ParseLocalName(parse_function_params)) return false;
+ ++m_read_ptr;
+ if (!ParseLocalName(parse_function_params))
+ return false;
break;
}
case 'L':
- ++read_ptr;
+ ++m_read_ptr;
// fallthrough
default:
{
- if (!ParseUnscopedName(name_state)) return false;
-
- if (*read_ptr == 'I')
+ if (!ParseUnscopedName(name_state))
+ return false;
+
+ if (*m_read_ptr == 'I')
{
EndSubstitution(name_start_cookie);
-
- ++read_ptr;
+
+ ++m_read_ptr;
name_state.is_last_generic = true;
WriteTemplateStart();
- if (!ParseTemplateArgs(parse_function_params)) return false;
+ if (!ParseTemplateArgs(parse_function_params))
+ return false;
WriteTemplateEnd();
}
break;
}
}
- if (parse_discriminator) TryParseDiscriminator();
+ if (parse_discriminator)
+ TryParseDiscriminator();
if (parse_function_params &&
- !ParseFunctionArgs(name_state, name_start_cookie)) return false;
+ !ParseFunctionArgs(name_state, name_start_cookie))
+ {
+ return false;
+ }
return true;
}
-
+
// <call-offset> ::= h <nv-offset> _
// ::= v <v-offset> _
//
@@ -1951,20 +2128,27 @@ private:
//
// <v-offset> ::= <offset number> _ <virtual offset number>
// # virtual base override, with vcall offset
-
- bool ParseCallOffset()
+
+ bool
+ ParseCallOffset()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'h':
- if (*read_ptr == 'n') ++read_ptr;
- if (TryParseNumber() == -1 || *read_ptr++ != '_') break;
+ if (*m_read_ptr == 'n')
+ ++m_read_ptr;
+ if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
+ break;
return true;
case 'v':
- if (*read_ptr == 'n') ++read_ptr;
- if (TryParseNumber() == -1 || *read_ptr++ != '_') break;
- if (*read_ptr == 'n') ++read_ptr;
- if (TryParseNumber() == -1 || *read_ptr++ != '_') break;
+ if (*m_read_ptr == 'n')
+ ++m_read_ptr;
+ if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
+ break;
+ if (*m_read_ptr == 'n')
+ ++m_read_ptr;
+ if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
+ break;
return true;
}
#ifdef DEBUG_FAILURES
@@ -1972,7 +2156,7 @@ private:
#endif
return false;
}
-
+
// <special-name> ::= TV <type> # virtual table
// ::= TT <type> # VTT structure (construction vtable index)
// ::= TI <type> # typeinfo structure
@@ -1984,10 +2168,11 @@ private:
// ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
-
- bool ParseSpecialNameT()
+
+ bool
+ ParseSpecialNameT()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'V':
WRITE("vtable for ");
@@ -2004,11 +2189,11 @@ private:
case 'c':
case 'C':
#ifdef DEBUG_FAILURES
- printf("*** Unsupported thunk or construction vtable name: %.3s\n", read_ptr - 1);
+ printf("*** Unsupported thunk or construction vtable name: %.3s\n", m_read_ptr - 1);
#endif
return false;
default:
- if (*--read_ptr == 'v')
+ if (*--m_read_ptr == 'v')
{
WRITE("virtual thunk to ");
}
@@ -2016,26 +2201,30 @@ private:
{
WRITE("non-virtual thunk to ");
}
- if (!ParseCallOffset()) return false;
+ if (!ParseCallOffset())
+ return false;
return ParseEncoding();
}
}
-
+
// <special-name> ::= GV <object name> # Guard variable for one-time initialization
// # No <type>
// extension ::= GR <object name> # reference temporary for object
-
- bool ParseSpecialNameG()
+
+ bool
+ ParseSpecialNameG()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'V':
WRITE("guard variable for ");
- if (!ParseName(true)) return false;
+ if (!ParseName(true))
+ return false;
break;
case 'R':
WRITE("reference temporary for ");
- if (!ParseName(true)) return false;
+ if (!ParseName(true))
+ return false;
break;
default:
#ifdef DEBUG_FAILURES
@@ -2045,58 +2234,64 @@ private:
}
return true;
}
-
+
// <bare-function-type> ::= <signature type>+ # types are possible return type, then parameter types
-
- bool ParseFunctionArgs(NameState & name_state, int return_insert_cookie)
+
+ bool
+ ParseFunctionArgs(NameState & name_state, int return_insert_cookie)
{
- char next = *read_ptr;
- if (next == 'E' || next == '\0' || next == '.') return true;
-
+ char next = *m_read_ptr;
+ if (next == 'E' || next == '\0' || next == '.')
+ return true;
+
// Clang has a bad habit of making unique manglings by just sticking numbers on the end of a symbol,
// which is ambiguous with malformed source name manglings
- const char * before_clang_uniquing_test = read_ptr;
+ const char *before_clang_uniquing_test = m_read_ptr;
if (TryParseNumber())
{
- if (*read_ptr == '\0') return true;
- read_ptr = before_clang_uniquing_test;
+ if (*m_read_ptr == '\0')
+ return true;
+ m_read_ptr = before_clang_uniquing_test;
}
-
+
if (name_state.is_last_generic && !name_state.has_no_return_type)
{
int return_type_start_cookie = GetStartCookie();
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
Write(' ');
ReorderRange(EndRange(return_type_start_cookie),
return_insert_cookie);
}
-
+
Write('(');
bool first_param = true;
while (true)
{
- switch (*read_ptr)
+ switch (*m_read_ptr)
{
case '\0':
case 'E':
case '.':
break;
case 'v':
- ++read_ptr;
+ ++m_read_ptr;
continue;
case '_':
// Not a formal part of the mangling specification, but clang emits suffixes starting with _block_invoke
- if (strncmp(read_ptr, "_block_invoke", 13) == 0)
+ if (strncmp(m_read_ptr, "_block_invoke", 13) == 0)
{
- read_ptr += strlen(read_ptr);
+ m_read_ptr += strlen(m_read_ptr);
break;
}
// fallthrough
default:
- if (first_param) first_param = false;
+ if (first_param)
+ first_param = false;
else WriteCommaSpace();
-
- if (!ParseType()) return false;
+
+ if (!ParseType())
+ return false;
continue;
}
break;
@@ -2104,53 +2299,60 @@ private:
Write(')');
return true;
}
-
+
// <encoding> ::= <function name> <bare-function-type>
// ::= <data name>
// ::= <special-name>
-
- bool ParseEncoding()
+
+ bool
+ ParseEncoding()
{
- switch (*read_ptr)
+ switch (*m_read_ptr)
{
case 'T':
- ++read_ptr;
- if (!ParseSpecialNameT()) return false;
+ ++m_read_ptr;
+ if (!ParseSpecialNameT())
+ return false;
break;
case 'G':
- ++read_ptr;
- if (!ParseSpecialNameG()) return false;
+ ++m_read_ptr;
+ if (!ParseSpecialNameG())
+ return false;
break;
default:
- if (!ParseName(true)) return false;
+ if (!ParseName(true))
+ return false;
break;
}
return true;
}
-
- bool ParseMangling(const char * mangled_name, long mangled_name_length = 0)
- {
- if (!mangled_name_length) mangled_name_length = strlen(mangled_name);
- read_end = mangled_name + mangled_name_length;
- read_ptr = mangled_name;
- write_ptr = buffer;
- next_substitute_index = 0;
- next_template_arg_index = rewrite_ranges_size - 1;
-
- if (*read_ptr++ != '_' || *read_ptr++ != 'Z')
+
+ bool
+ ParseMangling(const char *mangled_name, long mangled_name_length = 0)
+ {
+ if (!mangled_name_length)
+ mangled_name_length = strlen(mangled_name);
+ m_read_end = mangled_name + mangled_name_length;
+ m_read_ptr = mangled_name;
+ m_write_ptr = m_buffer;
+ m_next_substitute_index = 0;
+ m_next_template_arg_index = m_rewrite_ranges_size - 1;
+
+ if (*m_read_ptr++ != '_' || *m_read_ptr++ != 'Z')
{
#ifdef DEBUG_FAILURES
printf("*** Missing _Z prefix\n");
#endif
return false;
}
- if (!ParseEncoding()) return false;
- switch (*read_ptr)
+ if (!ParseEncoding())
+ return false;
+ switch (*m_read_ptr)
{
case '.':
Write(' ');
Write('(');
- Write(read_ptr, read_end - read_ptr);
+ Write(m_read_ptr, m_read_end - m_read_ptr);
Write(')');
case '\0':
return true;
@@ -2161,25 +2363,25 @@ private:
return false;
}
}
-
+
private:
-
+
// External scratch storage used during demanglings
-
- char * buffer;
- const char * buffer_end;
- BufferRange * rewrite_ranges;
- int rewrite_ranges_size;
- bool owns_buffer;
- bool owns_rewrite_ranges;
-
+
+ char *m_buffer;
+ const char *m_buffer_end;
+ BufferRange *m_rewrite_ranges;
+ int m_rewrite_ranges_size;
+ bool m_owns_buffer;
+ bool m_owns_m_rewrite_ranges;
+
// Internal state used during demangling
-
- const char * read_ptr;
- const char * read_end;
- char * write_ptr;
- int next_template_arg_index;
- int next_substitute_index;
+
+ const char *m_read_ptr;
+ const char *m_read_end;
+ char *m_write_ptr;
+ int m_next_template_arg_index;
+ int m_next_substitute_index;
};
} // Anonymous namespace
@@ -2187,17 +2389,19 @@ private:
// Public entry points referenced from Mangled.cpp
namespace lldb_private
{
- char * FastDemangle(const char* mangled_name)
+ char *
+ FastDemangle(const char *mangled_name)
{
char buffer[16384];
- SymbolDemangler demangler(buffer, sizeof(buffer));
+ SymbolDemangler demangler(buffer, sizeof (buffer));
return demangler.GetDemangledCopy(mangled_name);
}
- char * FastDemangle(const char* mangled_name, long mangled_name_length)
+ char *
+ FastDemangle(const char *mangled_name, long mangled_name_length)
{
char buffer[16384];
- SymbolDemangler demangler(buffer, sizeof(buffer));
+ SymbolDemangler demangler(buffer, sizeof (buffer));
return demangler.GetDemangledCopy(mangled_name, mangled_name_length);
}
} // lldb_private namespace
diff --git a/source/Core/FileSpecList.cpp b/source/Core/FileSpecList.cpp
index 0cec8faa6bc4..4b1c991c6be4 100644
--- a/source/Core/FileSpecList.cpp
+++ b/source/Core/FileSpecList.cpp
@@ -107,7 +107,7 @@ FileSpecList::Dump(Stream *s, const char *separator_cstr) const
// it is found, else UINT32_MAX is returned.
//------------------------------------------------------------------
size_t
-FileSpecList::FindFileIndex (size_t start_idx, const FileSpec &file_spec, bool full) const
+FileSpecList::FindFileIndex (size_t start_idx, const FileSpec &file_spec, bool full, bool remove_dots) const
{
const size_t num_files = m_files.size();
@@ -124,7 +124,7 @@ FileSpecList::FindFileIndex (size_t start_idx, const FileSpec &file_spec, bool f
}
else
{
- if (FileSpec::Equal (m_files[idx], file_spec, full))
+ if (FileSpec::Equal (m_files[idx], file_spec, full, remove_dots))
return idx;
}
}
diff --git a/source/Core/IOHandler.cpp b/source/Core/IOHandler.cpp
index add3ad8c5ba3..21ba965ba212 100644
--- a/source/Core/IOHandler.cpp
+++ b/source/Core/IOHandler.cpp
@@ -19,7 +19,9 @@
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObjectRegister.h"
+#ifndef LLDB_DISABLE_LIBEDIT
#include "lldb/Host/Editline.h"
+#endif
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/Block.h"
@@ -36,8 +38,9 @@
using namespace lldb;
using namespace lldb_private;
-IOHandler::IOHandler (Debugger &debugger) :
+IOHandler::IOHandler (Debugger &debugger, IOHandler::Type type) :
IOHandler (debugger,
+ type,
StreamFileSP(), // Adopt STDIN from top input reader
StreamFileSP(), // Adopt STDOUT from top input reader
StreamFileSP(), // Adopt STDERR from top input reader
@@ -47,6 +50,7 @@ IOHandler::IOHandler (Debugger &debugger) :
IOHandler::IOHandler (Debugger &debugger,
+ IOHandler::Type type,
const lldb::StreamFileSP &input_sp,
const lldb::StreamFileSP &output_sp,
const lldb::StreamFileSP &error_sp,
@@ -55,7 +59,9 @@ IOHandler::IOHandler (Debugger &debugger,
m_input_sp (input_sp),
m_output_sp (output_sp),
m_error_sp (error_sp),
+ m_popped (false),
m_flags (flags),
+ m_type (type),
m_user_data (NULL),
m_done (false),
m_active (false)
@@ -151,13 +157,28 @@ IOHandler::GetIsRealTerminal ()
return GetInputStreamFile()->GetFile().GetIsRealTerminal();
}
+void
+IOHandler::SetPopped (bool b)
+{
+ m_popped.SetValue(b, eBroadcastOnChange);
+}
+
+void
+IOHandler::WaitForPop ()
+{
+ m_popped.WaitForValueEqualTo(true);
+}
+
IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger,
const char *prompt,
bool default_response) :
IOHandlerEditline(debugger,
+ IOHandler::Type::Confirm,
NULL, // NULL editline_name means no history loaded/saved
- NULL,
+ NULL, // No prompt
+ NULL, // No continuation prompt
false, // Multi-line
+ false, // Don't colorize the prompt (i.e. the confirm message.)
0,
*this),
m_default_response (default_response),
@@ -310,83 +331,121 @@ IOHandlerDelegate::IOHandlerComplete (IOHandler &io_handler,
IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
+ IOHandler::Type type,
const char *editline_name, // Used for saving history files
const char *prompt,
+ const char *continuation_prompt,
bool multi_line,
+ bool color_prompts,
uint32_t line_number_start,
IOHandlerDelegate &delegate) :
IOHandlerEditline(debugger,
+ type,
StreamFileSP(), // Inherit input from top input reader
StreamFileSP(), // Inherit output from top input reader
StreamFileSP(), // Inherit error from top input reader
0, // Flags
editline_name, // Used for saving history files
prompt,
+ continuation_prompt,
multi_line,
+ color_prompts,
line_number_start,
delegate)
{
}
IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
+ IOHandler::Type type,
const lldb::StreamFileSP &input_sp,
const lldb::StreamFileSP &output_sp,
const lldb::StreamFileSP &error_sp,
uint32_t flags,
const char *editline_name, // Used for saving history files
const char *prompt,
+ const char *continuation_prompt,
bool multi_line,
+ bool color_prompts,
uint32_t line_number_start,
IOHandlerDelegate &delegate) :
- IOHandler (debugger, input_sp, output_sp, error_sp, flags),
+ IOHandler (debugger, type, input_sp, output_sp, error_sp, flags),
+#ifndef LLDB_DISABLE_LIBEDIT
m_editline_ap (),
+#endif
m_delegate (delegate),
m_prompt (),
+ m_continuation_prompt(),
+ m_current_lines_ptr (NULL),
m_base_line_number (line_number_start),
- m_multi_line (multi_line)
+ m_curr_line_idx (UINT32_MAX),
+ m_multi_line (multi_line),
+ m_color_prompts (color_prompts),
+ m_interrupt_exits (true)
{
SetPrompt(prompt);
+#ifndef LLDB_DISABLE_LIBEDIT
bool use_editline = false;
-#ifndef _MSC_VER
use_editline = m_input_sp->GetFile().GetIsRealTerminal();
-#else
- // Editline is causing issues on Windows, so use the fallback.
- use_editline = false;
-#endif
if (use_editline)
{
m_editline_ap.reset(new Editline (editline_name,
- prompt ? prompt : "",
- multi_line,
GetInputFILE (),
GetOutputFILE (),
- GetErrorFILE ()));
- if (m_base_line_number > 0)
- m_editline_ap->ShowLineNumbers(true, m_base_line_number);
- m_editline_ap->SetLineCompleteCallback (LineCompletedCallback, this);
+ GetErrorFILE (),
+ m_color_prompts));
+ m_editline_ap->SetIsInputCompleteCallback (IsInputCompleteCallback, this);
m_editline_ap->SetAutoCompleteCallback (AutoCompleteCallback, this);
+ // See if the delegate supports fixing indentation
+ const char *indent_chars = delegate.IOHandlerGetFixIndentationCharacters();
+ if (indent_chars)
+ {
+ // The delegate does support indentation, hook it up so when any indentation
+ // character is typed, the delegate gets a chance to fix it
+ m_editline_ap->SetFixIndentationCallback (FixIndentationCallback, this, indent_chars);
+ }
}
-
+#endif
+ SetBaseLineNumber (m_base_line_number);
+ SetPrompt(prompt ? prompt : "");
+ SetContinuationPrompt(continuation_prompt);
}
IOHandlerEditline::~IOHandlerEditline ()
{
+#ifndef LLDB_DISABLE_LIBEDIT
m_editline_ap.reset();
+#endif
+}
+
+void
+IOHandlerEditline::Activate ()
+{
+ IOHandler::Activate();
+ m_delegate.IOHandlerActivated(*this);
+}
+
+void
+IOHandlerEditline::Deactivate ()
+{
+ IOHandler::Deactivate();
+ m_delegate.IOHandlerDeactivated(*this);
}
bool
IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
{
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
{
- return m_editline_ap->GetLine(line, interrupted).Success();
+ return m_editline_ap->GetLine (line, interrupted);
}
else
{
+#endif
line.clear();
FILE *in = GetInputFILE();
@@ -394,7 +453,14 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
{
if (GetIsInteractive())
{
- const char *prompt = GetPrompt();
+ const char *prompt = NULL;
+
+ if (m_multi_line && m_curr_line_idx > 0)
+ prompt = GetContinuationPrompt();
+
+ if (prompt == NULL)
+ prompt = GetPrompt();
+
if (prompt && prompt[0])
{
FILE *out = GetOutputFILE();
@@ -452,19 +518,30 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
SetIsDone(true);
}
return false;
+#ifndef LLDB_DISABLE_LIBEDIT
}
+#endif
}
-LineStatus
-IOHandlerEditline::LineCompletedCallback (Editline *editline,
+#ifndef LLDB_DISABLE_LIBEDIT
+bool
+IOHandlerEditline::IsInputCompleteCallback (Editline *editline,
StringList &lines,
- uint32_t line_idx,
- Error &error,
void *baton)
{
IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
- return editline_reader->m_delegate.IOHandlerLinesUpdated(*editline_reader, lines, line_idx, error);
+ return editline_reader->m_delegate.IOHandlerIsInputComplete(*editline_reader, lines);
+}
+
+int
+IOHandlerEditline::FixIndentationCallback (Editline *editline,
+ const StringList &lines,
+ int cursor_position,
+ void *baton)
+{
+ IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
+ return editline_reader->m_delegate.IOHandlerFixIndentation(*editline_reader, lines, cursor_position);
}
int
@@ -487,14 +564,24 @@ IOHandlerEditline::AutoCompleteCallback (const char *current_line,
matches);
return 0;
}
+#endif
const char *
IOHandlerEditline::GetPrompt ()
{
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
+ {
return m_editline_ap->GetPrompt ();
- else if (m_prompt.empty())
- return NULL;
+ }
+ else
+ {
+#endif
+ if (m_prompt.empty())
+ return NULL;
+#ifndef LLDB_DISABLE_LIBEDIT
+ }
+#endif
return m_prompt.c_str();
}
@@ -505,34 +592,71 @@ IOHandlerEditline::SetPrompt (const char *p)
m_prompt = p;
else
m_prompt.clear();
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
m_editline_ap->SetPrompt (m_prompt.empty() ? NULL : m_prompt.c_str());
+#endif
return true;
}
+const char *
+IOHandlerEditline::GetContinuationPrompt ()
+{
+ if (m_continuation_prompt.empty())
+ return NULL;
+ return m_continuation_prompt.c_str();
+}
+
+
+void
+IOHandlerEditline::SetContinuationPrompt (const char *p)
+{
+ if (p && p[0])
+ m_continuation_prompt = p;
+ else
+ m_continuation_prompt.clear();
+
+#ifndef LLDB_DISABLE_LIBEDIT
+ if (m_editline_ap)
+ m_editline_ap->SetContinuationPrompt (m_continuation_prompt.empty() ? NULL : m_continuation_prompt.c_str());
+#endif
+}
+
+
void
IOHandlerEditline::SetBaseLineNumber (uint32_t line)
{
m_base_line_number = line;
+}
+
+uint32_t
+IOHandlerEditline::GetCurrentLineIndex () const
+{
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
- m_editline_ap->ShowLineNumbers (true, line);
-
+ return m_editline_ap->GetCurrentLine();
+#endif
+ return m_curr_line_idx;
}
+
bool
IOHandlerEditline::GetLines (StringList &lines, bool &interrupted)
{
+ m_current_lines_ptr = &lines;
+
bool success = false;
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
{
- std::string end_token;
- success = m_editline_ap->GetLines(end_token, lines, interrupted).Success();
+ return m_editline_ap->GetLines (m_base_line_number, lines, interrupted);
}
else
{
- LineStatus lines_status = LineStatus::Success;
+#endif
+ bool done = false;
Error error;
- while (lines_status == LineStatus::Success)
+ while (!done)
{
// Show line numbers if we are asked to
std::string line;
@@ -543,31 +667,23 @@ IOHandlerEditline::GetLines (StringList &lines, bool &interrupted)
::fprintf(out, "%u%s", m_base_line_number + (uint32_t)lines.GetSize(), GetPrompt() == NULL ? " " : "");
}
+ m_curr_line_idx = lines.GetSize();
+
bool interrupted = false;
- if (GetLine(line, interrupted))
+ if (GetLine(line, interrupted) && !interrupted)
{
- if (interrupted)
- {
- lines_status = LineStatus::Done;
- }
- else
- {
- lines.AppendString(line);
- lines_status = m_delegate.IOHandlerLinesUpdated(*this, lines, lines.GetSize() - 1, error);
- }
+ lines.AppendString(line);
+ done = m_delegate.IOHandlerIsInputComplete(*this, lines);
}
else
{
- lines_status = LineStatus::Done;
+ done = true;
}
}
-
- // Call the IOHandlerLinesUpdated function with UINT32_MAX as the line
- // number to indicate all lines are complete
- m_delegate.IOHandlerLinesUpdated(*this, lines, UINT32_MAX, error);
-
success = lines.GetSize() > 0;
+#ifndef LLDB_DISABLE_LIBEDIT
}
+#endif
return success;
}
@@ -588,12 +704,14 @@ IOHandlerEditline::Run ()
{
if (interrupted)
{
- m_done = true;
+ m_done = m_interrupt_exits;
+ m_delegate.IOHandlerInputInterrupted (*this, line);
+
}
else
{
line = lines.CopyList();
- m_delegate.IOHandlerInputComplete(*this, line);
+ m_delegate.IOHandlerInputComplete (*this, line);
}
}
else
@@ -605,8 +723,10 @@ IOHandlerEditline::Run ()
{
if (GetLine(line, interrupted))
{
- if (!interrupted)
- m_delegate.IOHandlerInputComplete(*this, line);
+ if (interrupted)
+ m_delegate.IOHandlerInputInterrupted (*this, line);
+ else
+ m_delegate.IOHandlerInputComplete (*this, line);
}
else
{
@@ -619,20 +739,24 @@ 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])
{
@@ -643,14 +767,18 @@ IOHandlerEditline::Refresh ()
::fflush(out);
}
}
+#ifndef LLDB_DISABLE_LIBEDIT
}
+#endif
}
void
IOHandlerEditline::Cancel ()
{
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
m_editline_ap->Interrupt ();
+#endif
}
bool
@@ -660,16 +788,20 @@ IOHandlerEditline::Interrupt ()
if (m_delegate.IOHandlerInterrupt(*this))
return true;
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
return m_editline_ap->Interrupt();
+#endif
return false;
}
void
IOHandlerEditline::GotEOF()
{
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
m_editline_ap->Interrupt();
+#endif
}
// we may want curses to be disabled for some builds
@@ -5333,7 +5465,7 @@ protected:
DisplayOptions ValueObjectListDelegate::g_options = { true };
IOHandlerCursesGUI::IOHandlerCursesGUI (Debugger &debugger) :
- IOHandler (debugger)
+ IOHandler (debugger, IOHandler::Type::Curses)
{
}
diff --git a/source/Core/Log.cpp b/source/Core/Log.cpp
index 3adca6e5385c..d205d363b764 100644
--- a/source/Core/Log.cpp
+++ b/source/Core/Log.cpp
@@ -26,9 +26,12 @@
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/Host.h"
-#include "lldb/Host/TimeValue.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/Host/ThisThread.h"
+#include "lldb/Host/TimeValue.h"
#include "lldb/Interpreter/Args.h"
+
+#include "llvm/ADT/SmallString.h"
using namespace lldb;
using namespace lldb_private;
@@ -113,7 +116,8 @@ Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
// Add the thread name if requested
if (m_options.Test (LLDB_LOG_OPTION_PREPEND_THREAD_NAME))
{
- std::string thread_name (Host::GetThreadName (getpid(), Host::GetCurrentThreadID()));
+ llvm::SmallString<32> thread_name;
+ ThisThread::GetName(thread_name);
if (!thread_name.empty())
header.Printf ("%s ", thread_name.c_str());
}
diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp
index c4fa10fedd86..c0ab66cd2880 100644
--- a/source/Core/Mangled.cpp
+++ b/source/Core/Mangled.cpp
@@ -4986,10 +4986,12 @@ __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/Timer.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
+
using namespace lldb_private;
static inline bool
@@ -5000,6 +5002,57 @@ cstring_is_mangled (const char *s)
return false;
}
+static const ConstString &
+get_demangled_name_without_arguments (const Mangled *obj)
+{
+ // This pair is <mangled name, demangled name without function arguments>
+ static std::pair<ConstString, ConstString> g_most_recent_mangled_to_name_sans_args;
+
+ // Need to have the mangled & demangled names we're currently examining as statics
+ // so we can return a const ref to them at the end of the func if we don't have
+ // anything better.
+ static ConstString g_last_mangled;
+ static ConstString g_last_demangled;
+
+ ConstString mangled = obj->GetMangledName ();
+ ConstString demangled = obj->GetDemangledName ();
+
+ if (mangled && g_most_recent_mangled_to_name_sans_args.first == mangled)
+ {
+ return g_most_recent_mangled_to_name_sans_args.second;
+ }
+
+ g_last_demangled = demangled;
+ g_last_mangled = mangled;
+
+ const char *mangled_name_cstr = mangled.GetCString();
+
+ if (demangled && mangled_name_cstr && mangled_name_cstr[0])
+ {
+ if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' &&
+ (mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure, typeinfo structure, and typeinfo mangled_name
+ mangled_name_cstr[2] != 'G' && // avoid guard variables
+ mangled_name_cstr[2] != 'Z')) // named local entities (if we eventually handle eSymbolTypeData, we will want this back)
+ {
+ CPPLanguageRuntime::MethodName cxx_method (demangled);
+ if (!cxx_method.GetBasename().empty() && !cxx_method.GetContext().empty())
+ {
+ std::string shortname = cxx_method.GetContext().str();
+ shortname += "::";
+ shortname += cxx_method.GetBasename().str();
+ ConstString result(shortname.c_str());
+ g_most_recent_mangled_to_name_sans_args.first = mangled;
+ g_most_recent_mangled_to_name_sans_args.second = result;
+ return g_most_recent_mangled_to_name_sans_args.second;
+ }
+ }
+ }
+
+ if (demangled)
+ return g_last_demangled;
+ return g_last_mangled;
+}
+
#pragma mark Mangled
//----------------------------------------------------------------------
// Default constructor
@@ -5215,6 +5268,14 @@ Mangled::NameMatches (const RegularExpression& regex) const
const ConstString&
Mangled::GetName (Mangled::NamePreference preference) const
{
+ if (preference == ePreferDemangledWithoutArguments)
+ {
+ // Call the accessor to make sure we get a demangled name in case
+ // it hasn't been demangled yet...
+ GetDemangledName();
+
+ return get_demangled_name_without_arguments (this);
+ }
if (preference == ePreferDemangled)
{
// Call the accessor to make sure we get a demangled name in case
diff --git a/source/Core/Module.cpp b/source/Core/Module.cpp
index 6f16ada49824..900eea2e0419 100644
--- a/source/Core/Module.cpp
+++ b/source/Core/Module.cpp
@@ -1309,6 +1309,10 @@ Module::GetObjectFile()
// unknown.
m_objfile_sp->GetArchitecture (m_arch);
}
+ else
+ {
+ ReportError ("failed to load objfile for %s", GetFileSpec().GetPath().c_str());
+ }
}
}
return m_objfile_sp.get();
@@ -1706,8 +1710,9 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
const char *name_cstr = name.GetCString();
lookup_name_type_mask = eFunctionNameTypeNone;
match_name_after_lookup = false;
- const char *base_name_start = NULL;
- const char *base_name_end = NULL;
+
+ llvm::StringRef basename;
+ llvm::StringRef context;
if (name_type_mask & eFunctionNameTypeAuto)
{
@@ -1721,16 +1726,16 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
lookup_name_type_mask |= eFunctionNameTypeSelector;
CPPLanguageRuntime::MethodName cpp_method (name);
- llvm::StringRef basename (cpp_method.GetBasename());
+ basename = cpp_method.GetBasename();
if (basename.empty())
{
- if (CPPLanguageRuntime::StripNamespacesFromVariableName (name_cstr, base_name_start, base_name_end))
+ if (CPPLanguageRuntime::ExtractContextAndIdentifier (name_cstr, context, basename))
lookup_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
+ else
+ lookup_name_type_mask = eFunctionNameTypeFull;
}
else
{
- base_name_start = basename.data();
- base_name_end = base_name_start + basename.size();
lookup_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
}
}
@@ -1745,9 +1750,7 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
CPPLanguageRuntime::MethodName cpp_method (name);
if (cpp_method.IsValid())
{
- llvm::StringRef basename (cpp_method.GetBasename());
- base_name_start = basename.data();
- base_name_end = base_name_start + basename.size();
+ basename = cpp_method.GetBasename();
if (!cpp_method.GetQualifiers().empty())
{
@@ -1760,12 +1763,9 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
}
else
{
- if (!CPPLanguageRuntime::StripNamespacesFromVariableName (name_cstr, base_name_start, base_name_end))
- {
- lookup_name_type_mask &= ~(eFunctionNameTypeMethod | eFunctionNameTypeBase);
- if (lookup_name_type_mask == eFunctionNameTypeNone)
- return;
- }
+ // If the CPP method parser didn't manage to chop this up, try to fill in the base name if we can.
+ // If a::b::c is passed in, we need to just look up "c", and then we'll filter the result later.
+ CPPLanguageRuntime::ExtractContextAndIdentifier (name_cstr, context, basename);
}
}
@@ -1780,16 +1780,13 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
}
}
- if (base_name_start &&
- base_name_end &&
- base_name_start != name_cstr &&
- base_name_start < base_name_end)
+ if (!basename.empty())
{
// The name supplied was a partial C++ path like "a::count". In this case we want to do a
// lookup on the basename "count" and then make sure any matching results contain "a::count"
// so that it would match "b::a::count" and "a::count". This is why we set "match_name_after_lookup"
// to true
- lookup_name.SetCStringWithLength(base_name_start, base_name_end - base_name_start);
+ lookup_name.SetString(basename);
match_name_after_lookup = true;
}
else
diff --git a/source/Core/ModuleList.cpp b/source/Core/ModuleList.cpp
index 156f3cf9d0aa..879eb9bd1822 100644
--- a/source/Core/ModuleList.cpp
+++ b/source/Core/ModuleList.cpp
@@ -484,6 +484,26 @@ ModuleList::FindFunctionSymbols (const ConstString &name,
return sc_list.GetSize() - old_size;
}
+
+size_t
+ModuleList::FindFunctions(const RegularExpression &name,
+ bool include_symbols,
+ bool include_inlines,
+ bool append,
+ SymbolContextList& sc_list)
+{
+ const size_t old_size = sc_list.GetSize();
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindFunctions (name, include_symbols, include_inlines, append, sc_list);
+ }
+
+ return sc_list.GetSize() - old_size;
+}
+
size_t
ModuleList::FindCompileUnits (const FileSpec &path,
bool append,
diff --git a/source/Core/PluginManager.cpp b/source/Core/PluginManager.cpp
index cda55802fab8..95574cb2deaf 100644
--- a/source/Core/PluginManager.cpp
+++ b/source/Core/PluginManager.cpp
@@ -2068,6 +2068,229 @@ PluginManager::GetUnwindAssemblyCreateCallbackForPluginName (const ConstString &
return NULL;
}
+#pragma mark MemoryHistory
+
+struct MemoryHistoryInstance
+{
+ MemoryHistoryInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ MemoryHistoryCreateInstance create_callback;
+};
+
+typedef std::vector<MemoryHistoryInstance> MemoryHistoryInstances;
+
+static Mutex &
+GetMemoryHistoryMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static MemoryHistoryInstances &
+GetMemoryHistoryInstances ()
+{
+ static MemoryHistoryInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ MemoryHistoryCreateInstance create_callback
+ )
+{
+ if (create_callback)
+ {
+ MemoryHistoryInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetMemoryHistoryMutex ());
+ GetMemoryHistoryInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (MemoryHistoryCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetMemoryHistoryMutex ());
+ MemoryHistoryInstances &instances = GetMemoryHistoryInstances ();
+
+ MemoryHistoryInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+MemoryHistoryCreateInstance
+PluginManager::GetMemoryHistoryCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetMemoryHistoryMutex ());
+ MemoryHistoryInstances &instances = GetMemoryHistoryInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+MemoryHistoryCreateInstance
+PluginManager::GetMemoryHistoryCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetMemoryHistoryMutex ());
+ MemoryHistoryInstances &instances = GetMemoryHistoryInstances ();
+
+ MemoryHistoryInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark InstrumentationRuntime
+
+struct InstrumentationRuntimeInstance
+{
+ InstrumentationRuntimeInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ InstrumentationRuntimeCreateInstance create_callback;
+ InstrumentationRuntimeGetType get_type_callback;
+};
+
+typedef std::vector<InstrumentationRuntimeInstance> InstrumentationRuntimeInstances;
+
+static Mutex &
+GetInstrumentationRuntimeMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static InstrumentationRuntimeInstances &
+GetInstrumentationRuntimeInstances ()
+{
+ static InstrumentationRuntimeInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ InstrumentationRuntimeCreateInstance create_callback,
+ InstrumentationRuntimeGetType get_type_callback
+ )
+{
+ if (create_callback)
+ {
+ InstrumentationRuntimeInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.get_type_callback = get_type_callback;
+ Mutex::Locker locker (GetInstrumentationRuntimeMutex ());
+ GetInstrumentationRuntimeInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (InstrumentationRuntimeCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetInstrumentationRuntimeMutex ());
+ InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances ();
+
+ InstrumentationRuntimeInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+InstrumentationRuntimeGetType
+PluginManager::GetInstrumentationRuntimeGetTypeCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetInstrumentationRuntimeMutex ());
+ InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances ();
+ if (idx < instances.size())
+ return instances[idx].get_type_callback;
+ return NULL;
+}
+
+InstrumentationRuntimeCreateInstance
+PluginManager::GetInstrumentationRuntimeCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetInstrumentationRuntimeMutex ());
+ InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+InstrumentationRuntimeCreateInstance
+PluginManager::GetInstrumentationRuntimeCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetInstrumentationRuntimeMutex ());
+ InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances ();
+
+ InstrumentationRuntimeInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark PluginManager
+
void
PluginManager::DebuggerInitialize (Debugger &debugger)
{
diff --git a/source/Core/RegularExpression.cpp b/source/Core/RegularExpression.cpp
index 88415f616828..54924d069537 100644
--- a/source/Core/RegularExpression.cpp
+++ b/source/Core/RegularExpression.cpp
@@ -162,20 +162,11 @@ RegularExpression::Execute(const char* s, Match *match, int execute_flags) const
bool
RegularExpression::Match::GetMatchAtIndex (const char* s, uint32_t idx, std::string& match_str) const
{
- if (idx < m_matches.size())
+ llvm::StringRef match_str_ref;
+ if (GetMatchAtIndex(s, idx, match_str_ref))
{
- if (m_matches[idx].rm_eo == m_matches[idx].rm_so)
- {
- // Matched the empty string...
- match_str.clear();
- return true;
- }
- else if (m_matches[idx].rm_eo > m_matches[idx].rm_so)
- {
- match_str.assign (s + m_matches[idx].rm_so,
- m_matches[idx].rm_eo - m_matches[idx].rm_so);
- return true;
- }
+ match_str = std::move(match_str_ref.str());
+ return true;
}
return false;
}
@@ -185,6 +176,9 @@ RegularExpression::Match::GetMatchAtIndex (const char* s, uint32_t idx, llvm::St
{
if (idx < m_matches.size())
{
+ if (m_matches[idx].rm_eo == -1 && m_matches[idx].rm_so == -1)
+ return false;
+
if (m_matches[idx].rm_eo == m_matches[idx].rm_so)
{
// Matched the empty string...
diff --git a/source/Core/SearchFilter.cpp b/source/Core/SearchFilter.cpp
index dee2f2e4bd5e..9c3412a422d0 100644
--- a/source/Core/SearchFilter.cpp
+++ b/source/Core/SearchFilter.cpp
@@ -119,6 +119,15 @@ SearchFilter::Dump (Stream *s) const
}
+lldb::SearchFilterSP
+SearchFilter::CopyForBreakpoint (Breakpoint &breakpoint)
+{
+ SearchFilterSP ret_sp = DoCopyForBreakpoint (breakpoint);
+ TargetSP target_sp = breakpoint.GetTargetSP();
+ ret_sp->SetTarget(target_sp);
+ return ret_sp;
+}
+
//----------------------------------------------------------------------
// UTILITY Functions to help iterate down through the elements of the
// SymbolContext.
@@ -281,29 +290,36 @@ SearchFilter::DoFunctionIteration (Function *function, const SymbolContext &cont
}
//----------------------------------------------------------------------
-// SearchFilterForNonModuleSpecificSearches:
+// SearchFilterForUnconstrainedSearches:
// Selects a shared library matching a given file spec, consulting the targets "black list".
//----------------------------------------------------------------------
- bool
- SearchFilterForNonModuleSpecificSearches::ModulePasses (const FileSpec &module_spec)
- {
- if (m_target_sp->ModuleIsExcludedForNonModuleSpecificSearches (module_spec))
- return false;
- else
- return true;
- }
-
- bool
- SearchFilterForNonModuleSpecificSearches::ModulePasses (const lldb::ModuleSP &module_sp)
- {
- if (!module_sp)
- return true;
- else if (m_target_sp->ModuleIsExcludedForNonModuleSpecificSearches (module_sp))
- return false;
- else
- return true;
- }
+bool
+SearchFilterForUnconstrainedSearches::ModulePasses (const FileSpec &module_spec)
+{
+ if (m_target_sp->ModuleIsExcludedForUnconstrainedSearches (module_spec))
+ return false;
+ else
+ return true;
+}
+
+bool
+SearchFilterForUnconstrainedSearches::ModulePasses (const lldb::ModuleSP &module_sp)
+{
+ if (!module_sp)
+ return true;
+ else if (m_target_sp->ModuleIsExcludedForUnconstrainedSearches (module_sp))
+ return false;
+ else
+ return true;
+}
+
+lldb::SearchFilterSP
+SearchFilterForUnconstrainedSearches::DoCopyForBreakpoint (Breakpoint &breakpoint)
+{
+ SearchFilterSP ret_sp(new SearchFilterForUnconstrainedSearches(*this));
+ return ret_sp;
+}
//----------------------------------------------------------------------
// SearchFilterByModule:
@@ -434,7 +450,7 @@ SearchFilterByModule::GetDescription (Stream *s)
}
else
{
- s->PutCString(m_module_spec.GetFilename().AsCString("<unknown>"));
+ s->PutCString(m_module_spec.GetFilename().AsCString("<Unknown>"));
}
}
@@ -449,6 +465,14 @@ SearchFilterByModule::Dump (Stream *s) const
{
}
+
+lldb::SearchFilterSP
+SearchFilterByModule::DoCopyForBreakpoint (Breakpoint &breakpoint)
+{
+ SearchFilterSP ret_sp(new SearchFilterByModule(*this));
+ return ret_sp;
+}
+
//----------------------------------------------------------------------
// SearchFilterByModuleList:
// Selects a shared library matching a given file spec
@@ -458,7 +482,8 @@ SearchFilterByModule::Dump (Stream *s) const
// SearchFilterByModuleList constructors
//----------------------------------------------------------------------
-SearchFilterByModuleList::SearchFilterByModuleList (const lldb::TargetSP &target_sp, const FileSpecList &module_list) :
+SearchFilterByModuleList::SearchFilterByModuleList (const lldb::TargetSP &target_sp,
+ const FileSpecList &module_list) :
SearchFilter (target_sp),
m_module_spec_list (module_list)
{
@@ -587,7 +612,7 @@ SearchFilterByModuleList::GetDescription (Stream *s)
}
else
{
- s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<unknown>"));
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<Unknown>"));
}
}
else
@@ -603,7 +628,7 @@ SearchFilterByModuleList::GetDescription (Stream *s)
}
else
{
- s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<unknown>"));
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<Unknown>"));
}
if (i != num_modules - 1)
s->PutCString (", ");
@@ -623,6 +648,14 @@ SearchFilterByModuleList::Dump (Stream *s) const
}
+lldb::SearchFilterSP
+SearchFilterByModuleList::DoCopyForBreakpoint (Breakpoint &breakpoint)
+{
+ SearchFilterSP ret_sp(new SearchFilterByModuleList(*this));
+ return ret_sp;
+}
+
+
//----------------------------------------------------------------------
// SearchFilterByModuleListAndCU:
// Selects a shared library matching a given file spec
@@ -778,7 +811,7 @@ SearchFilterByModuleListAndCU::GetDescription (Stream *s)
}
else
{
- s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<unknown>"));
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<Unknown>"));
}
}
else if (num_modules > 0)
@@ -794,7 +827,7 @@ SearchFilterByModuleListAndCU::GetDescription (Stream *s)
}
else
{
- s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<unknown>"));
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<Unknown>"));
}
if (i != num_modules - 1)
s->PutCString (", ");
@@ -814,3 +847,10 @@ SearchFilterByModuleListAndCU::Dump (Stream *s) const
}
+lldb::SearchFilterSP
+SearchFilterByModuleListAndCU::DoCopyForBreakpoint (Breakpoint &breakpoint)
+{
+ SearchFilterSP ret_sp(new SearchFilterByModuleListAndCU(*this));
+ return ret_sp;
+}
+
diff --git a/source/Core/Section.cpp b/source/Core/Section.cpp
index 3267c1866221..ea33a62b775f 100644
--- a/source/Core/Section.cpp
+++ b/source/Core/Section.cpp
@@ -28,7 +28,8 @@ Section::Section (const ModuleSP &module_sp,
lldb::offset_t file_offset,
lldb::offset_t file_size,
uint32_t log2align,
- uint32_t flags) :
+ uint32_t flags,
+ uint32_t target_byte_size/*=1*/) :
ModuleChild (module_sp),
UserID (sect_id),
Flags (flags),
@@ -44,7 +45,8 @@ Section::Section (const ModuleSP &module_sp,
m_children (),
m_fake (false),
m_encrypted (false),
- m_thread_specific (false)
+ m_thread_specific (false),
+ m_target_byte_size(target_byte_size)
{
// printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ", addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s\n",
// this, module_sp.get(), sect_id, file_addr, file_addr + byte_size, file_offset, file_offset + file_size, flags, name.GetCString());
@@ -61,7 +63,8 @@ Section::Section (const lldb::SectionSP &parent_section_sp,
lldb::offset_t file_offset,
lldb::offset_t file_size,
uint32_t log2align,
- uint32_t flags) :
+ uint32_t flags,
+ uint32_t target_byte_size/*=1*/) :
ModuleChild (module_sp),
UserID (sect_id),
Flags (flags),
@@ -77,7 +80,8 @@ Section::Section (const lldb::SectionSP &parent_section_sp,
m_children (),
m_fake (false),
m_encrypted (false),
- m_thread_specific (false)
+ m_thread_specific (false),
+ m_target_byte_size(target_byte_size)
{
// printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ", addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s.%s\n",
// this, module_sp.get(), sect_id, file_addr, file_addr + byte_size, file_offset, file_offset + file_size, flags, parent_section_sp->GetName().GetCString(), name.GetCString());
@@ -186,7 +190,7 @@ Section::ContainsFileAddress (addr_t vm_addr) const
{
if (file_addr <= vm_addr)
{
- const addr_t offset = vm_addr - file_addr;
+ const addr_t offset = (vm_addr - file_addr) * m_target_byte_size;
return offset < GetByteSize();
}
}
diff --git a/source/Core/StreamString.cpp b/source/Core/StreamString.cpp
index 8d7d039fd65c..ef2b70583ebd 100644
--- a/source/Core/StreamString.cpp
+++ b/source/Core/StreamString.cpp
@@ -65,6 +65,22 @@ StreamString::GetSize () const
return m_packet.size();
}
+size_t
+StreamString::GetSizeOfLastLine () const
+{
+ const size_t length = m_packet.size();
+ size_t last_line_begin_pos = m_packet.find_last_of("\r\n");
+ if (last_line_begin_pos == std::string::npos)
+ {
+ return length;
+ }
+ else
+ {
+ ++last_line_begin_pos;
+ return length - last_line_begin_pos;
+ }
+}
+
std::string &
StreamString::GetString()
{
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
index 1819e834536a..fa5fb14db05b 100644
--- a/source/Core/ValueObject.cpp
+++ b/source/Core/ValueObject.cpp
@@ -34,8 +34,12 @@
#include "lldb/Core/ValueObjectSyntheticFilter.h"
#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/ValueObjectPrinter.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
+
#include "lldb/Host/Endian.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -43,6 +47,7 @@
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/ExecutionContext.h"
@@ -77,6 +82,7 @@ ValueObject::ValueObject (ValueObject &parent) :
m_location_str (),
m_summary_str (),
m_object_desc_str (),
+ m_validation_result(),
m_manager(parent.GetManager()),
m_children (),
m_synthetic_children (),
@@ -89,8 +95,10 @@ ValueObject::ValueObject (ValueObject &parent) :
m_type_summary_sp(),
m_type_format_sp(),
m_synthetic_children_sp(),
+ m_type_validator_sp(),
m_user_id_of_forced_summary(),
m_address_type_of_ptr_or_ref_children(eAddressTypeInvalid),
+ m_value_checksum(),
m_value_is_valid (false),
m_value_did_change (false),
m_children_count_valid (false),
@@ -100,7 +108,8 @@ ValueObject::ValueObject (ValueObject &parent) :
m_is_bitfield_for_scalar(false),
m_is_child_at_offset(false),
m_is_getting_summary(false),
- m_did_calculate_complete_objc_class_type(false)
+ m_did_calculate_complete_objc_class_type(false),
+ m_is_synthetic_children_generated(parent.m_is_synthetic_children_generated)
{
m_manager->ManageObject(this);
}
@@ -123,6 +132,7 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope,
m_location_str (),
m_summary_str (),
m_object_desc_str (),
+ m_validation_result(),
m_manager(),
m_children (),
m_synthetic_children (),
@@ -135,8 +145,10 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope,
m_type_summary_sp(),
m_type_format_sp(),
m_synthetic_children_sp(),
+ m_type_validator_sp(),
m_user_id_of_forced_summary(),
m_address_type_of_ptr_or_ref_children(child_ptr_or_ref_addr_type),
+ m_value_checksum(),
m_value_is_valid (false),
m_value_did_change (false),
m_children_count_valid (false),
@@ -146,7 +158,8 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope,
m_is_bitfield_for_scalar(false),
m_is_child_at_offset(false),
m_is_getting_summary(false),
- m_did_calculate_complete_objc_class_type(false)
+ m_did_calculate_complete_objc_class_type(false),
+ m_is_synthetic_children_generated(false)
{
m_manager = new ValueObjectManager();
m_manager->ManageObject (this);
@@ -181,7 +194,7 @@ ValueObject::UpdateValueIfNeeded (bool update_format)
return m_error.Success();
}
- bool first_update = m_update_point.IsFirstEvaluation();
+ bool first_update = IsChecksumEmpty();
if (m_update_point.NeedsUpdating())
{
@@ -210,10 +223,35 @@ ValueObject::UpdateValueIfNeeded (bool update_format)
m_error.Clear();
// Call the pure virtual function to update the value
+
+ bool need_compare_checksums = false;
+ llvm::SmallVector<uint8_t, 16> old_checksum;
+
+ if (!first_update && CanProvideValue())
+ {
+ need_compare_checksums = true;
+ old_checksum.resize(m_value_checksum.size());
+ std::copy(m_value_checksum.begin(), m_value_checksum.end(), old_checksum.begin());
+ }
+
bool success = UpdateValue ();
SetValueIsValid (success);
+ if (success)
+ {
+ const uint64_t max_checksum_size = 128;
+ m_data.Checksum(m_value_checksum,
+ max_checksum_size);
+ }
+ else
+ {
+ need_compare_checksums = false;
+ m_value_checksum.clear();
+ }
+
+ assert (!need_compare_checksums || (!old_checksum.empty() && !m_value_checksum.empty()));
+
if (first_update)
SetValueDidChange (false);
else if (!m_value_did_change && success == false)
@@ -222,6 +260,11 @@ ValueObject::UpdateValueIfNeeded (bool update_format)
// as changed if the value used to be valid and now isn't
SetValueDidChange (value_was_valid);
}
+ else if (need_compare_checksums)
+ {
+ SetValueDidChange(memcmp(&old_checksum[0], &m_value_checksum[0], m_value_checksum.size()));
+ }
+
}
else
{
@@ -253,6 +296,7 @@ ValueObject::UpdateFormatsIfNeeded()
#ifndef LLDB_DISABLE_PYTHON
SetSyntheticChildren(DataVisualization::GetSyntheticChildren (*this, GetDynamicValueType()));
#endif
+ SetValidator(DataVisualization::GetValidator(*this, GetDynamicValueType()));
}
return any_change;
@@ -486,7 +530,6 @@ ValueObject::SetValueIsValid (bool b)
bool
ValueObject::GetValueDidChange ()
{
- GetValueAsCString ();
return m_value_did_change;
}
@@ -746,9 +789,9 @@ ValueObject::MightHaveChildren()
const uint32_t type_info = GetTypeInfo();
if (type_info)
{
- if (type_info & (ClangASTType::eTypeHasChildren |
- ClangASTType::eTypeIsPointer |
- ClangASTType::eTypeIsReference))
+ if (type_info & (eTypeHasChildren |
+ eTypeIsPointer |
+ eTypeIsReference))
has_children = true;
}
else
@@ -835,6 +878,14 @@ bool
ValueObject::GetSummaryAsCString (TypeSummaryImpl* summary_ptr,
std::string& destination)
{
+ return GetSummaryAsCString(summary_ptr, destination, TypeSummaryOptions());
+}
+
+bool
+ValueObject::GetSummaryAsCString (TypeSummaryImpl* summary_ptr,
+ std::string& destination,
+ const TypeSummaryOptions& options)
+{
destination.clear();
// ideally we would like to bail out if passing NULL, but if we do so
@@ -851,66 +902,11 @@ ValueObject::GetSummaryAsCString (TypeSummaryImpl* summary_ptr,
GetName().GetCString(),
summary_ptr->GetDescription().c_str());*/
- if (UpdateValueIfNeeded (false))
+ if (UpdateValueIfNeeded (false) && summary_ptr)
{
- if (summary_ptr)
- {
- if (HasSyntheticValue())
- m_synthetic_value->UpdateValueIfNeeded(); // the summary might depend on the synthetic children being up-to-date (e.g. ${svar%#})
- summary_ptr->FormatObject(this, destination);
- }
- else
- {
- ClangASTType clang_type = GetClangType();
-
- // Do some default printout for function pointers
- if (clang_type)
- {
- if (clang_type.IsFunctionPointerType ())
- {
- StreamString sstr;
- AddressType func_ptr_address_type = eAddressTypeInvalid;
- addr_t func_ptr_address = GetPointerValue (&func_ptr_address_type);
- if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS)
- {
- switch (func_ptr_address_type)
- {
- case eAddressTypeInvalid:
- case eAddressTypeFile:
- break;
-
- case eAddressTypeLoad:
- {
- ExecutionContext exe_ctx (GetExecutionContextRef());
-
- Address so_addr;
- Target *target = exe_ctx.GetTargetPtr();
- if (target && target->GetSectionLoadList().IsEmpty() == false)
- {
- if (target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address, so_addr))
- {
- so_addr.Dump (&sstr,
- exe_ctx.GetBestExecutionContextScope(),
- Address::DumpStyleResolvedDescription,
- Address::DumpStyleSectionNameOffset);
- }
- }
- }
- break;
-
- case eAddressTypeHost:
- break;
- }
- }
- if (sstr.GetSize() > 0)
- {
- destination.assign (1, '(');
- destination.append (sstr.GetData(), sstr.GetSize());
- destination.append (1, ')');
- }
- }
- }
- }
+ if (HasSyntheticValue())
+ m_synthetic_value->UpdateValueIfNeeded(); // the summary might depend on the synthetic children being up-to-date (e.g. ${svar%#})
+ summary_ptr->FormatObject(this, destination, options);
}
m_is_getting_summary = false;
return !destination.empty();
@@ -922,7 +918,8 @@ ValueObject::GetSummaryAsCString ()
if (UpdateValueIfNeeded(true) && m_summary_str.empty())
{
GetSummaryAsCString(GetSummaryFormat().get(),
- m_summary_str);
+ m_summary_str,
+ TypeSummaryOptions());
}
if (m_summary_str.empty())
return NULL;
@@ -930,17 +927,26 @@ ValueObject::GetSummaryAsCString ()
}
bool
+ValueObject::GetSummaryAsCString (std::string& destination,
+ const TypeSummaryOptions& options)
+{
+ return GetSummaryAsCString(GetSummaryFormat().get(),
+ destination,
+ options);
+}
+
+bool
ValueObject::IsCStringContainer(bool check_pointer)
{
ClangASTType pointee_or_element_clang_type;
const Flags type_flags (GetTypeInfo (&pointee_or_element_clang_type));
- bool is_char_arr_ptr (type_flags.AnySet (ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer) &&
+ bool is_char_arr_ptr (type_flags.AnySet (eTypeIsArray | eTypeIsPointer) &&
pointee_or_element_clang_type.IsCharType ());
if (!is_char_arr_ptr)
return false;
if (!check_pointer)
return true;
- if (type_flags.Test(ClangASTType::eTypeIsArray))
+ if (type_flags.Test(eTypeIsArray))
return true;
addr_t cstr_address = LLDB_INVALID_ADDRESS;
AddressType cstr_address_type = eAddressTypeInvalid;
@@ -955,8 +961,8 @@ ValueObject::GetPointeeData (DataExtractor& data,
{
ClangASTType pointee_or_element_clang_type;
const uint32_t type_info = GetTypeInfo (&pointee_or_element_clang_type);
- const bool is_pointer_type = type_info & ClangASTType::eTypeIsPointer;
- const bool is_array_type = type_info & ClangASTType::eTypeIsArray;
+ const bool is_pointer_type = type_info & eTypeIsPointer;
+ const bool is_array_type = type_info & eTypeIsArray;
if (!(is_pointer_type || is_array_type))
return 0;
@@ -1182,20 +1188,31 @@ strlen_or_inf (const char* str,
return len;
}
+static bool
+CopyStringDataToBufferSP(const StreamString& source,
+ lldb::DataBufferSP& destination)
+{
+ destination.reset(new DataBufferHeap(source.GetSize()+1,0));
+ memcpy(destination->GetBytes(), source.GetString().c_str(), source.GetSize());
+ return true;
+}
+
size_t
-ValueObject::ReadPointedString (Stream& s,
+ValueObject::ReadPointedString (lldb::DataBufferSP& buffer_sp,
Error& error,
uint32_t max_length,
bool honor_array,
Format item_format)
{
+ StreamString s;
ExecutionContext exe_ctx (GetExecutionContextRef());
Target* target = exe_ctx.GetTargetPtr();
-
+
if (!target)
{
s << "<no target to read from>";
error.SetErrorString("no target to read from");
+ CopyStringDataToBufferSP(s, buffer_sp);
return 0;
}
@@ -1208,7 +1225,7 @@ ValueObject::ReadPointedString (Stream& s,
ClangASTType clang_type = GetClangType();
ClangASTType elem_or_pointee_clang_type;
const Flags type_flags (GetTypeInfo (&elem_or_pointee_clang_type));
- if (type_flags.AnySet (ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer) &&
+ if (type_flags.AnySet (eTypeIsArray | eTypeIsPointer) &&
elem_or_pointee_clang_type.IsCharType ())
{
addr_t cstr_address = LLDB_INVALID_ADDRESS;
@@ -1216,7 +1233,7 @@ ValueObject::ReadPointedString (Stream& s,
size_t cstr_len = 0;
bool capped_data = false;
- if (type_flags.Test (ClangASTType::eTypeIsArray))
+ if (type_flags.Test (eTypeIsArray))
{
// We have an array
uint64_t array_size = 0;
@@ -1241,9 +1258,10 @@ ValueObject::ReadPointedString (Stream& s,
{
s << "<invalid address>";
error.SetErrorString("invalid address");
+ CopyStringDataToBufferSP(s, buffer_sp);
return 0;
}
-
+
Address cstr_so_addr (cstr_address);
DataExtractor data;
if (cstr_len > 0 && honor_array)
@@ -1251,30 +1269,21 @@ ValueObject::ReadPointedString (Stream& s,
// I am using GetPointeeData() here to abstract the fact that some ValueObjects are actually frozen pointers in the host
// but the pointed-to data lives in the debuggee, and GetPointeeData() automatically takes care of this
GetPointeeData(data, 0, cstr_len);
-
+
if ((bytes_read = data.GetByteSize()) > 0)
{
total_bytes_read = bytes_read;
- s << '"';
- data.Dump (&s,
- 0, // Start offset in "data"
- item_format,
- 1, // Size of item (1 byte for a char!)
- bytes_read, // How many bytes to print?
- UINT32_MAX, // num per line
- LLDB_INVALID_ADDRESS,// base address
- 0, // bitfield bit size
- 0); // bitfield bit offset
+ for (size_t offset = 0; offset < bytes_read; offset++)
+ s.Printf("%c", *data.PeekData(offset, 1));
if (capped_data)
s << "...";
- s << '"';
}
}
else
{
cstr_len = max_length;
const size_t k_max_buf_size = 64;
-
+
size_t offset = 0;
int cstr_len_displayed = -1;
@@ -1288,12 +1297,10 @@ ValueObject::ReadPointedString (Stream& s,
size_t len = strlen_or_inf (cstr, k_max_buf_size, k_max_buf_size+1);
if (len > k_max_buf_size)
len = k_max_buf_size;
- if (cstr && cstr_len_displayed < 0)
- s << '"';
-
+
if (cstr_len_displayed < 0)
cstr_len_displayed = len;
-
+
if (len == 0)
break;
cstr_len_displayed += len;
@@ -1302,15 +1309,8 @@ ValueObject::ReadPointedString (Stream& s,
if (len > cstr_len)
len = cstr_len;
- data.Dump (&s,
- 0, // Start offset in "data"
- item_format,
- 1, // Size of item (1 byte for a char!)
- len, // How many bytes to print?
- UINT32_MAX, // num per line
- LLDB_INVALID_ADDRESS,// base address
- 0, // bitfield bit size
- 0); // bitfield bit offset
+ for (size_t offset = 0; offset < bytes_read; offset++)
+ s.Printf("%c", *data.PeekData(offset, 1));
if (len < k_max_buf_size)
break;
@@ -1320,14 +1320,13 @@ ValueObject::ReadPointedString (Stream& s,
capped_cstr = true;
break;
}
-
+
cstr_len -= len;
offset += len;
}
if (cstr_len_displayed >= 0)
{
- s << '"';
if (capped_cstr)
s << "...";
}
@@ -1338,9 +1337,27 @@ ValueObject::ReadPointedString (Stream& s,
error.SetErrorString("not a string object");
s << "<not a string object>";
}
+ CopyStringDataToBufferSP(s, buffer_sp);
return total_bytes_read;
}
+std::pair<TypeValidatorResult, std::string>
+ValueObject::GetValidationStatus ()
+{
+ if (!UpdateValueIfNeeded(true))
+ return {TypeValidatorResult::Success,""}; // not the validator's job to discuss update problems
+
+ if (m_validation_result.hasValue())
+ return m_validation_result.getValue();
+
+ if (!m_type_validator_sp)
+ return {TypeValidatorResult::Success,""}; // no validator no failure
+
+ auto outcome = m_type_validator_sp->FormatObject(this);
+
+ return (m_validation_result = {outcome.m_result,outcome.m_message}).getValue();
+}
+
const char *
ValueObject::GetObjectDescription ()
{
@@ -1428,7 +1445,7 @@ ValueObject::GetValueAsCString ()
}
else
{
- my_format = GetClangType().GetFormat();
+ my_format = GetValue().GetClangType().GetFormat();
}
}
}
@@ -1460,7 +1477,7 @@ uint64_t
ValueObject::GetValueAsUnsigned (uint64_t fail_value, bool *success)
{
// If our byte size is zero this is an aggregate type that has children
- if (!GetClangType().IsAggregateType())
+ if (CanProvideValue())
{
Scalar scalar;
if (ResolveValue (scalar))
@@ -1481,7 +1498,7 @@ int64_t
ValueObject::GetValueAsSigned (int64_t fail_value, bool *success)
{
// If our byte size is zero this is an aggregate type that has children
- if (!GetClangType().IsAggregateType())
+ if (CanProvideValue())
{
Scalar scalar;
if (ResolveValue (scalar))
@@ -1506,7 +1523,7 @@ ValueObject::HasSpecialPrintableRepresentation(ValueObjectRepresentationStyle va
Format custom_format)
{
Flags flags(GetTypeInfo());
- if (flags.AnySet(ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer)
+ if (flags.AnySet(eTypeIsArray | eTypeIsPointer)
&& val_obj_display == ValueObject::eValueObjectRepresentationStyleValue)
{
if (IsCStringContainer(true) &&
@@ -1516,7 +1533,7 @@ ValueObject::HasSpecialPrintableRepresentation(ValueObjectRepresentationStyle va
custom_format == eFormatVectorOfChar))
return true;
- if (flags.Test(ClangASTType::eTypeIsArray))
+ if (flags.Test(eTypeIsArray))
{
if ((custom_format == eFormatBytes) ||
(custom_format == eFormatBytesWithASCII))
@@ -1555,7 +1572,7 @@ ValueObject::DumpPrintableRepresentation(Stream& s,
if (allow_special)
{
- if (flags.AnySet(ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer)
+ if (flags.AnySet(eTypeIsArray | eTypeIsPointer)
&& val_obj_display == ValueObject::eValueObjectRepresentationStyleValue)
{
// when being asked to get a printable display an array or pointer type directly,
@@ -1568,11 +1585,19 @@ ValueObject::DumpPrintableRepresentation(Stream& s,
custom_format == eFormatVectorOfChar)) // print char[] & char* directly
{
Error error;
- ReadPointedString(s,
+ lldb::DataBufferSP buffer_sp;
+ ReadPointedString(buffer_sp,
error,
0,
(custom_format == eFormatVectorOfChar) ||
(custom_format == eFormatCharArray));
+ lldb_private::formatters::ReadBufferAndDumpToStreamOptions options(*this);
+ options.SetData(DataExtractor(buffer_sp, lldb::eByteOrderInvalid, 8)); // none of this matters for a string - pass some defaults
+ options.SetStream(&s);
+ options.SetPrefixToken(0);
+ options.SetQuote('"');
+ options.SetSourceSize(buffer_sp->GetByteSize());
+ lldb_private::formatters::ReadBufferAndDumpToStream<lldb_private::formatters::StringElementType::ASCII>(options);
return !error.Fail();
}
@@ -1581,7 +1606,7 @@ ValueObject::DumpPrintableRepresentation(Stream& s,
// this only works for arrays, because I have no way to know when
// the pointed memory ends, and no special \0 end of data marker
- if (flags.Test(ClangASTType::eTypeIsArray))
+ if (flags.Test(eTypeIsArray))
{
if ((custom_format == eFormatBytes) ||
(custom_format == eFormatBytesWithASCII))
@@ -1729,7 +1754,7 @@ ValueObject::DumpPrintableRepresentation(Stream& s,
cstr = GetSummaryAsCString();
else if (val_obj_display == eValueObjectRepresentationStyleSummary)
{
- if (GetClangType().IsAggregateType())
+ if (!CanProvideValue())
{
strm.Printf("%s @ %s", GetTypeName().AsCString(), GetLocationAsCString());
cstr = strm.GetString().c_str();
@@ -2037,7 +2062,7 @@ ValueObject::IsPossibleDynamicType ()
bool
ValueObject::IsObjCNil ()
{
- const uint32_t mask = ClangASTType::eTypeIsObjC | ClangASTType::eTypeIsPointer;
+ const uint32_t mask = eTypeIsObjC | eTypeIsPointer;
bool isObjCpointer = (((GetClangType().GetTypeInfo(NULL)) & mask) == mask);
if (!isObjCpointer)
return false;
@@ -2050,10 +2075,10 @@ ValueObjectSP
ValueObject::GetSyntheticArrayMember (size_t index, bool can_create)
{
const uint32_t type_info = GetTypeInfo ();
- if (type_info & ClangASTType::eTypeIsArray)
+ if (type_info & eTypeIsArray)
return GetSyntheticArrayMemberFromArray(index, can_create);
- if (type_info & ClangASTType::eTypeIsPointer)
+ if (type_info & eTypeIsPointer)
return GetSyntheticArrayMemberFromPointer(index, can_create);
return ValueObjectSP();
@@ -2460,6 +2485,46 @@ ValueObject::IsBaseClass (uint32_t& depth)
void
ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat epformat)
{
+ // synthetic children do not actually "exist" as part of the hierarchy, and sometimes they are consed up in ways
+ // that don't make sense from an underlying language/API standpoint. So, use a special code path here to return
+ // something that can hopefully be used in expression
+ if (m_is_synthetic_children_generated)
+ {
+ UpdateValueIfNeeded();
+
+ if (m_value.GetValueType() == Value::eValueTypeLoadAddress)
+ {
+ if (IsPointerOrReferenceType())
+ {
+ s.Printf("((%s)0x%" PRIx64 ")",
+ GetTypeName().AsCString("void"),
+ GetValueAsUnsigned(0));
+ return;
+ }
+ else
+ {
+ uint64_t load_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ s.Printf("(*( (%s *)0x%" PRIx64 "))",
+ GetTypeName().AsCString("void"),
+ load_addr);
+ return;
+ }
+ }
+ }
+
+ if (CanProvideValue())
+ {
+ s.Printf("((%s)%s)",
+ GetTypeName().AsCString("void"),
+ GetValueAsCString());
+ return;
+ }
+
+ return;
+ }
+
const bool is_deref_of_parent = IsDereferenceOfParent ();
if (is_deref_of_parent && epformat == eGetExpressionPathFormatDereferencePointers)
@@ -2499,12 +2564,12 @@ ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExp
{
const uint32_t non_base_class_parent_type_info = non_base_class_parent_clang_type.GetTypeInfo();
- if (non_base_class_parent_type_info & ClangASTType::eTypeIsPointer)
+ if (non_base_class_parent_type_info & eTypeIsPointer)
{
s.PutCString("->");
}
- else if ((non_base_class_parent_type_info & ClangASTType::eTypeHasChildren) &&
- !(non_base_class_parent_type_info & ClangASTType::eTypeIsArray))
+ else if ((non_base_class_parent_type_info & eTypeHasChildren) &&
+ !(non_base_class_parent_type_info & eTypeIsArray))
{
s.PutChar('.');
}
@@ -2728,15 +2793,15 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
case '-':
{
if (options.m_check_dot_vs_arrow_syntax &&
- root_clang_type_info.Test(ClangASTType::eTypeIsPointer) ) // if you are trying to use -> on a non-pointer and I must catch the error
+ root_clang_type_info.Test(eTypeIsPointer) ) // if you are trying to use -> on a non-pointer and I must catch the error
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrowInsteadOfDot;
*final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
return ValueObjectSP();
}
- if (root_clang_type_info.Test(ClangASTType::eTypeIsObjC) && // if yo are trying to extract an ObjC IVar when this is forbidden
- root_clang_type_info.Test(ClangASTType::eTypeIsPointer) &&
+ if (root_clang_type_info.Test(eTypeIsObjC) && // if yo are trying to extract an ObjC IVar when this is forbidden
+ root_clang_type_info.Test(eTypeIsPointer) &&
options.m_no_fragile_ivar)
{
*first_unparsed = expression_cstr;
@@ -2756,7 +2821,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
case '.': // or fallthrough from ->
{
if (options.m_check_dot_vs_arrow_syntax && *expression_cstr == '.' &&
- root_clang_type_info.Test(ClangASTType::eTypeIsPointer)) // if you are trying to use . on a pointer and I must catch the error
+ root_clang_type_info.Test(eTypeIsPointer)) // if you are trying to use . on a pointer and I must catch the error
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonDotInsteadOfArrow;
@@ -2783,7 +2848,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
if (root->IsSynthetic())
{
*first_unparsed = expression_cstr;
- *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchSyntheticChild;
*final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
return ValueObjectSP();
}
@@ -2857,9 +2922,9 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
}
case '[':
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray) && !root_clang_type_info.Test(ClangASTType::eTypeIsPointer) && !root_clang_type_info.Test(ClangASTType::eTypeIsVector)) // if this is not a T[] nor a T*
+ if (!root_clang_type_info.Test(eTypeIsArray) && !root_clang_type_info.Test(eTypeIsPointer) && !root_clang_type_info.Test(eTypeIsVector)) // if this is not a T[] nor a T*
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // if this is not even a scalar...
+ 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
{
@@ -2879,7 +2944,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
}
if (*(expression_cstr+1) == ']') // if this is an unbounded range it only works for arrays
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (!root_clang_type_info.Test(eTypeIsArray))
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
@@ -2916,7 +2981,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
}
if (end - expression_cstr == 1) // if this is [], only return a valid value for arrays
{
- if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (root_clang_type_info.Test(eTypeIsArray))
{
*first_unparsed = expression_cstr+2;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet;
@@ -2932,7 +2997,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
}
}
// from here on we do have a valid index
- if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (root_clang_type_info.Test(eTypeIsArray))
{
ValueObjectSP child_valobj_sp = root->GetChildAtIndex(index, true);
if (!child_valobj_sp)
@@ -2955,10 +3020,10 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
return ValueObjectSP();
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer))
+ else if (root_clang_type_info.Test(eTypeIsPointer))
{
if (*what_next == ValueObject::eExpressionPathAftermathDereference && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
- pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ pointee_clang_type_info.Test(eTypeIsScalar))
{
Error error;
root = root->Dereference(error);
@@ -2978,7 +3043,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
else
{
if (root->GetClangType().GetMinimumLanguage() == eLanguageTypeObjC
- && pointee_clang_type_info.AllClear(ClangASTType::eTypeIsPointer)
+ && pointee_clang_type_info.AllClear(eTypeIsPointer)
&& root->HasSyntheticValue()
&& options.m_no_synthetic_children == false)
{
@@ -3001,7 +3066,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
}
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ else if (root_clang_type_info.Test(eTypeIsScalar))
{
root = root->GetSyntheticBitFieldChild(index, index, true);
if (!root.get())
@@ -3019,7 +3084,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
return root;
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsVector))
+ else if (root_clang_type_info.Test(eTypeIsVector))
{
root = root->GetChildAtIndex(index, true);
if (!root.get())
@@ -3104,7 +3169,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
index_lower = index_higher;
index_higher = temp;
}
- if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // expansion only works for scalars
+ if (root_clang_type_info.Test(eTypeIsScalar)) // expansion only works for scalars
{
root = root->GetSyntheticBitFieldChild(index_lower, index_higher, true);
if (!root.get())
@@ -3122,9 +3187,9 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
return root;
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
+ else if (root_clang_type_info.Test(eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
*what_next == ValueObject::eExpressionPathAftermathDereference &&
- pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ pointee_clang_type_info.Test(eTypeIsScalar))
{
Error error;
root = root->Dereference(error);
@@ -3201,9 +3266,9 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
{
case '[':
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray) && !root_clang_type_info.Test(ClangASTType::eTypeIsPointer)) // if this is not a T[] nor a T*
+ if (!root_clang_type_info.Test(eTypeIsArray) && !root_clang_type_info.Test(eTypeIsPointer)) // if this is not a T[] nor a T*
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // if this is not even a scalar, this syntax is just plain wrong!
+ if (!root_clang_type_info.Test(eTypeIsScalar)) // if this is not even a scalar, this syntax is just plain wrong!
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid;
@@ -3220,7 +3285,7 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
}
if (*(expression_cstr+1) == ']') // if this is an unbounded range it only works for arrays
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (!root_clang_type_info.Test(eTypeIsArray))
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
@@ -3264,7 +3329,7 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
}
if (end - expression_cstr == 1) // if this is [], only return a valid value for arrays
{
- if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (root_clang_type_info.Test(eTypeIsArray))
{
const size_t max_index = root->GetNumChildren() - 1;
for (size_t index = 0; index < max_index; index++)
@@ -3287,7 +3352,7 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
}
}
// from here on we do have a valid index
- if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (root_clang_type_info.Test(eTypeIsArray))
{
root = root->GetChildAtIndex(index, true);
if (!root.get())
@@ -3306,10 +3371,10 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
return 1;
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer))
+ else if (root_clang_type_info.Test(eTypeIsPointer))
{
if (*what_next == ValueObject::eExpressionPathAftermathDereference && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
- pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ pointee_clang_type_info.Test(eTypeIsScalar))
{
Error error;
root = root->Dereference(error);
@@ -3391,7 +3456,7 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
index_lower = index_higher;
index_higher = temp;
}
- if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // expansion only works for scalars
+ if (root_clang_type_info.Test(eTypeIsScalar)) // expansion only works for scalars
{
root = root->GetSyntheticBitFieldChild(index_lower, index_higher, true);
if (!root.get())
@@ -3410,9 +3475,9 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
return 1;
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
+ else if (root_clang_type_info.Test(eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
*what_next == ValueObject::eExpressionPathAftermathDereference &&
- pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ pointee_clang_type_info.Test(eTypeIsScalar))
{
Error error;
root = root->Dereference(error);
@@ -3480,9 +3545,7 @@ ValueObject::LogValueObject (Log *log, const DumpValueObjectOptions& options)
void
ValueObject::Dump (Stream &s)
{
-
- ValueObjectPrinter printer(this,&s,DumpValueObjectOptions::DefaultOptions());
- printer.PrintValueObject();
+ Dump (s, DumpValueObjectOptions::DefaultOptions());
}
void
@@ -3529,6 +3592,55 @@ ValueObject::CreateConstantValue (const ConstString &name)
return valobj_sp;
}
+ValueObjectSP
+ValueObject::GetQualifiedRepresentationIfAvailable (lldb::DynamicValueType dynValue,
+ bool synthValue)
+{
+ ValueObjectSP result_sp(GetSP());
+
+ switch (dynValue)
+ {
+ case lldb::eDynamicCanRunTarget:
+ case lldb::eDynamicDontRunTarget:
+ {
+ if (!result_sp->IsDynamic())
+ {
+ if (result_sp->GetDynamicValue(dynValue))
+ result_sp = result_sp->GetDynamicValue(dynValue);
+ }
+ }
+ break;
+ case lldb::eNoDynamicValues:
+ {
+ if (result_sp->IsDynamic())
+ {
+ if (result_sp->GetStaticValue())
+ result_sp = result_sp->GetStaticValue();
+ }
+ }
+ break;
+ }
+
+ if (synthValue)
+ {
+ if (!result_sp->IsSynthetic())
+ {
+ if (result_sp->GetSyntheticValue())
+ result_sp = result_sp->GetSyntheticValue();
+ }
+ }
+ else
+ {
+ if (result_sp->IsSynthetic())
+ {
+ if (result_sp->GetNonSyntheticValue())
+ result_sp = result_sp->GetNonSyntheticValue();
+ }
+ }
+
+ return result_sp;
+}
+
lldb::addr_t
ValueObject::GetCPPVTableAddress (AddressType &address_type)
{
@@ -3538,13 +3650,13 @@ ValueObject::GetCPPVTableAddress (AddressType &address_type)
if (type_info)
{
bool ptr_or_ref = false;
- if (type_info & (ClangASTType::eTypeIsPointer | ClangASTType::eTypeIsReference))
+ if (type_info & (eTypeIsPointer | eTypeIsReference))
{
ptr_or_ref = true;
type_info = pointee_type.GetTypeInfo();
}
- const uint32_t cpp_class = ClangASTType::eTypeIsClass | ClangASTType::eTypeIsCPlusPlus;
+ const uint32_t cpp_class = eTypeIsClass | eTypeIsCPlusPlus;
if ((type_info & cpp_class) == cpp_class)
{
if (ptr_or_ref)
@@ -3736,16 +3848,14 @@ ValueObject::CastPointerType (const char *name, TypeSP &type_sp)
ValueObject::EvaluationPoint::EvaluationPoint () :
m_mod_id(),
m_exe_ctx_ref(),
- m_needs_update (true),
- m_first_update (true)
+ m_needs_update (true)
{
}
ValueObject::EvaluationPoint::EvaluationPoint (ExecutionContextScope *exe_scope, bool use_selected):
m_mod_id(),
m_exe_ctx_ref(),
- m_needs_update (true),
- m_first_update (true)
+ m_needs_update (true)
{
ExecutionContext exe_ctx(exe_scope);
TargetSP target_sp (exe_ctx.GetTargetSP());
@@ -3789,8 +3899,7 @@ ValueObject::EvaluationPoint::EvaluationPoint (ExecutionContextScope *exe_scope,
ValueObject::EvaluationPoint::EvaluationPoint (const ValueObject::EvaluationPoint &rhs) :
m_mod_id(),
m_exe_ctx_ref(rhs.m_exe_ctx_ref),
- m_needs_update (true),
- m_first_update (true)
+ m_needs_update (true)
{
}
@@ -3884,7 +3993,6 @@ ValueObject::EvaluationPoint::SetUpdated ()
ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
if (process_sp)
m_mod_id = process_sp->GetModID();
- m_first_update = false;
m_needs_update = false;
}
@@ -3900,9 +4008,7 @@ ValueObject::ClearUserVisibleData(uint32_t clear_mask)
m_location_str.clear();
if ((clear_mask & eClearUserVisibleDataItemsSummary) == eClearUserVisibleDataItemsSummary)
- {
m_summary_str.clear();
- }
if ((clear_mask & eClearUserVisibleDataItemsDescription) == eClearUserVisibleDataItemsDescription)
m_object_desc_str.clear();
@@ -3912,6 +4018,9 @@ ValueObject::ClearUserVisibleData(uint32_t clear_mask)
if (m_synthetic_value)
m_synthetic_value = NULL;
}
+
+ if ((clear_mask & eClearUserVisibleDataItemsValidator) == eClearUserVisibleDataItemsValidator)
+ m_validation_result.reset();
}
SymbolContextScope *
@@ -3930,6 +4039,16 @@ ValueObject::CreateValueObjectFromExpression (const char* name,
const char* expression,
const ExecutionContext& exe_ctx)
{
+ return CreateValueObjectFromExpression(name, expression, exe_ctx, EvaluateExpressionOptions());
+}
+
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromExpression (const char* name,
+ const char* expression,
+ const ExecutionContext& exe_ctx,
+ const EvaluateExpressionOptions& options)
+{
lldb::ValueObjectSP retval_sp;
lldb::TargetSP target_sp(exe_ctx.GetTargetSP());
if (!target_sp)
@@ -3938,7 +4057,8 @@ ValueObject::CreateValueObjectFromExpression (const char* name,
return retval_sp;
target_sp->EvaluateExpression (expression,
exe_ctx.GetFrameSP().get(),
- retval_sp);
+ retval_sp,
+ options);
if (retval_sp && name && *name)
retval_sp->SetName(ConstString(name));
return retval_sp;
@@ -3960,7 +4080,7 @@ ValueObject::CreateValueObjectFromAddress (const char* name,
pointer_type,
ConstString(name),
buffer,
- lldb::endian::InlHostByteOrder(),
+ exe_ctx.GetByteOrder(),
exe_ctx.GetAddressByteSize()));
if (ptr_result_valobj_sp)
{
@@ -4057,3 +4177,77 @@ ValueObject::GetFormat () const
}
return m_format;
}
+
+lldb::LanguageType
+ValueObject::GetPreferredDisplayLanguage ()
+{
+ lldb::LanguageType type = lldb::eLanguageTypeUnknown;
+ if (GetRoot())
+ {
+ if (GetRoot() == this)
+ {
+ if (StackFrameSP frame_sp = GetFrameSP())
+ {
+ const SymbolContext& sc(frame_sp->GetSymbolContext(eSymbolContextCompUnit));
+ if (CompileUnit* cu = sc.comp_unit)
+ type = cu->GetLanguage();
+ }
+ }
+ else
+ {
+ type = GetRoot()->GetPreferredDisplayLanguage();
+ }
+ }
+ return type;
+}
+
+bool
+ValueObject::CanProvideValue ()
+{
+ // we need to support invalid types as providers of values because some bare-board
+ // debugging scenarios have no notion of types, but still manage to have raw numeric
+ // values for things like registers. sigh.
+ const ClangASTType &type(GetClangType());
+ return (false == type.IsValid()) || (0 != (type.GetTypeInfo() & eTypeHasValue));
+}
+
+bool
+ValueObject::IsChecksumEmpty ()
+{
+ return m_value_checksum.empty();
+}
+
+ValueObjectSP
+ValueObject::Persist ()
+{
+ if (!UpdateValueIfNeeded())
+ return nullptr;
+
+ TargetSP target_sp(GetTargetSP());
+ if (!target_sp)
+ return nullptr;
+
+ ConstString name(target_sp->GetPersistentVariables().GetNextPersistentVariableName());
+
+ ClangExpressionVariableSP clang_var_sp(new ClangExpressionVariable(target_sp.get(), GetValue(), name));
+ if (clang_var_sp)
+ {
+ clang_var_sp->m_live_sp = clang_var_sp->m_frozen_sp;
+ clang_var_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference;
+ target_sp->GetPersistentVariables().AddVariable(clang_var_sp);
+ }
+
+ return clang_var_sp->GetValueObject();
+}
+
+bool
+ValueObject::IsSyntheticChildrenGenerated ()
+{
+ return m_is_synthetic_children_generated;
+}
+
+void
+ValueObject::SetSyntheticChildrenGenerated (bool b)
+{
+ m_is_synthetic_children_generated = b;
+}
diff --git a/source/Core/ValueObjectCast.cpp b/source/Core/ValueObjectCast.cpp
index 4f4f8cc681d0..b20371b128df 100644
--- a/source/Core/ValueObjectCast.cpp
+++ b/source/Core/ValueObjectCast.cpp
@@ -102,7 +102,7 @@ ValueObjectCast::UpdateValue ()
//m_value.SetContext (Value::eContextTypeClangType, clang_type);
m_value.SetClangType (clang_type);
SetAddressTypeOfChildren(m_parent->GetAddressTypeOfChildren());
- if (clang_type.IsAggregateType ())
+ if (!CanProvideValue())
{
// this value object represents an aggregate type whose
// children have values, but this object does not. So we
diff --git a/source/Core/ValueObjectChild.cpp b/source/Core/ValueObjectChild.cpp
index 33b91f9e30d1..2b3c8344af8f 100644
--- a/source/Core/ValueObjectChild.cpp
+++ b/source/Core/ValueObjectChild.cpp
@@ -208,7 +208,7 @@ ValueObjectChild::UpdateValue ()
{
const bool thread_and_frame_only_if_stopped = true;
ExecutionContext exe_ctx (GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));
- if (GetClangType().GetTypeInfo() & ClangASTType::eTypeHasValue)
+ if (GetClangType().GetTypeInfo() & lldb::eTypeHasValue)
m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
else
m_error.Clear(); // No value so nothing to read...
diff --git a/source/Core/ValueObjectConstResult.cpp b/source/Core/ValueObjectConstResult.cpp
index 387e171e3526..fc870d726221 100644
--- a/source/Core/ValueObjectConstResult.cpp
+++ b/source/Core/ValueObjectConstResult.cpp
@@ -122,9 +122,10 @@ ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
ValueObjectSP
ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
Value &value,
- const ConstString &name)
+ const ConstString &name,
+ Module *module)
{
- return (new ValueObjectConstResult (exe_scope, value, name))->GetSP();
+ return (new ValueObjectConstResult (exe_scope, value, name, module))->GetSP();
}
ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
@@ -222,14 +223,18 @@ ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope
ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
const Value &value,
- const ConstString &name) :
+ const ConstString &name,
+ Module *module) :
ValueObject (exe_scope),
m_type_name (),
m_byte_size (0),
m_impl(this)
{
m_value = value;
- m_value.GetData(m_data);
+ m_name = name;
+ ExecutionContext exe_ctx;
+ exe_scope->CalculateExecutionContext(exe_ctx);
+ m_error = m_value.GetValueAsData(&exe_ctx, m_data, 0, module);
}
ValueObjectConstResult::~ValueObjectConstResult()
@@ -358,3 +363,8 @@ ValueObjectConstResult::GetDynamicValue (lldb::DynamicValueType use_dynamic)
return ValueObjectSP();
}
+lldb::LanguageType
+ValueObjectConstResult::GetPreferredDisplayLanguage ()
+{
+ return lldb::eLanguageTypeUnknown;
+}
diff --git a/source/Core/ValueObjectConstResultImpl.cpp b/source/Core/ValueObjectConstResultImpl.cpp
index d3e275883509..733d767b7ee1 100644
--- a/source/Core/ValueObjectConstResultImpl.cpp
+++ b/source/Core/ValueObjectConstResultImpl.cpp
@@ -30,13 +30,6 @@
using namespace lldb;
using namespace lldb_private;
-// this macro enables a simpler implementation for some method calls in this object that relies only upon
-// ValueObject knowing how to set the address type of its children correctly. the alternative implementation
-// relies on being able to create a target copy of the frozen object, which makes it less bug-prone but less
-// efficient as well. once we are confident the faster implementation is bug-free, this macro (and the slower
-// implementations) can go
-#define TRIVIAL_IMPL 1
-
ValueObjectConstResultImpl::ValueObjectConstResultImpl (ValueObject* valobj,
lldb::addr_t live_address) :
m_impl_backend(valobj),
@@ -48,38 +41,12 @@ ValueObjectConstResultImpl::ValueObjectConstResultImpl (ValueObject* valobj,
}
lldb::ValueObjectSP
-ValueObjectConstResultImpl::DerefOnTarget()
-{
- if (m_load_addr_backend.get() == NULL)
- {
- lldb::addr_t tgt_address = m_impl_backend->GetPointerValue();
- ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
- m_load_addr_backend = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
- m_impl_backend->GetClangType(),
- m_impl_backend->GetName(),
- tgt_address,
- eAddressTypeLoad,
- exe_ctx.GetAddressByteSize());
- }
- return m_load_addr_backend;
-}
-
-lldb::ValueObjectSP
ValueObjectConstResultImpl::Dereference (Error &error)
{
if (m_impl_backend == NULL)
return lldb::ValueObjectSP();
-#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
return m_impl_backend->ValueObject::Dereference(error);
-#else
- m_impl_backend->UpdateValueIfNeeded(false);
-
- if (NeedsDerefOnTarget())
- return DerefOnTarget()->Dereference(error);
- else
- return m_impl_backend->ValueObject::Dereference(error);
-#endif
}
ValueObject *
@@ -139,7 +106,8 @@ ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array
child_bitfield_bit_offset,
child_is_base_class,
child_is_deref_of_parent);
- valobj->m_impl.SetLiveAddress(m_live_address+child_byte_offset);
+ if (m_live_address != LLDB_INVALID_ADDRESS)
+ valobj->m_impl.SetLiveAddress(m_live_address+child_byte_offset);
}
return valobj;
@@ -151,16 +119,7 @@ ValueObjectConstResultImpl::GetSyntheticChildAtOffset (uint32_t offset, const Cl
if (m_impl_backend == NULL)
return lldb::ValueObjectSP();
-#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
return m_impl_backend->ValueObject::GetSyntheticChildAtOffset(offset, type, can_create);
-#else
- m_impl_backend->UpdateValueIfNeeded(false);
-
- if (NeedsDerefOnTarget())
- return DerefOnTarget()->GetSyntheticChildAtOffset(offset, type, can_create);
- else
- return m_impl_backend->ValueObject::GetSyntheticChildAtOffset(offset, type, can_create);
-#endif
}
lldb::ValueObjectSP
@@ -193,7 +152,7 @@ ValueObjectConstResultImpl::AddressOf (Error &error)
return m_address_of_backend;
}
else
- return lldb::ValueObjectSP();
+ return m_impl_backend->ValueObject::AddressOf(error);
}
lldb::addr_t
@@ -223,14 +182,5 @@ ValueObjectConstResultImpl::GetPointeeData (DataExtractor& data,
{
if (m_impl_backend == NULL)
return 0;
-#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
return m_impl_backend->ValueObject::GetPointeeData(data, item_idx, item_count);
-#else
- m_impl_backend->UpdateValueIfNeeded(false);
-
- if (NeedsDerefOnTarget() && m_impl_backend->IsPointerType())
- return DerefOnTarget()->GetPointeeData(data, item_idx, item_count);
- else
- return m_impl_backend->ValueObject::GetPointeeData(data, item_idx, item_count);
-#endif
}
diff --git a/source/Core/ValueObjectDynamicValue.cpp b/source/Core/ValueObjectDynamicValue.cpp
index a6fad7a9b1fd..1b8ec8083f8f 100644
--- a/source/Core/ValueObjectDynamicValue.cpp
+++ b/source/Core/ValueObjectDynamicValue.cpp
@@ -241,16 +241,7 @@ ValueObjectDynamicValue::UpdateValue ()
{
if (class_type_or_name.HasType())
{
- // TypeSP are always generated from debug info
- if (!class_type_or_name.HasTypeSP() && class_type_or_name.GetClangASTType().IsRuntimeGeneratedType())
- {
- m_type_impl = TypeImpl(m_parent->GetClangType(),FixupTypeAndOrName(class_type_or_name, *m_parent).GetClangASTType());
- class_type_or_name.SetClangASTType(ClangASTType());
- }
- else
- {
- m_type_impl = TypeImpl(FixupTypeAndOrName(class_type_or_name, *m_parent).GetClangASTType());
- }
+ m_type_impl = TypeImpl(m_parent->GetClangType(),FixupTypeAndOrName(class_type_or_name, *m_parent).GetClangASTType());
}
else
{
@@ -329,7 +320,7 @@ ValueObjectDynamicValue::UpdateValue ()
m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
if (m_error.Success())
{
- if (GetClangType().IsAggregateType ())
+ if (!CanProvideValue())
{
// this value object represents an aggregate type whose
// children have values, but this object does not. So we
diff --git a/source/Core/ValueObjectMemory.cpp b/source/Core/ValueObjectMemory.cpp
index d2cbbfdda240..5fbe87b66522 100644
--- a/source/Core/ValueObjectMemory.cpp
+++ b/source/Core/ValueObjectMemory.cpp
@@ -233,7 +233,7 @@ ValueObjectMemory::UpdateValue ()
}
}
- if (GetClangType().IsAggregateType())
+ if (!CanProvideValue())
{
// this value object represents an aggregate type whose
// children have values, but this object does not. So we
diff --git a/source/Core/ValueObjectSyntheticFilter.cpp b/source/Core/ValueObjectSyntheticFilter.cpp
index 18d36164989a..dafe73a5e57e 100644
--- a/source/Core/ValueObjectSyntheticFilter.cpp
+++ b/source/Core/ValueObjectSyntheticFilter.cpp
@@ -66,16 +66,17 @@ ValueObjectSynthetic::ValueObjectSynthetic (ValueObject &parent, lldb::Synthetic
m_name_toindex(),
m_synthetic_children_count(UINT32_MAX),
m_parent_type_name(parent.GetTypeName()),
- m_might_have_children(eLazyBoolCalculate)
+ m_might_have_children(eLazyBoolCalculate),
+ m_provides_value(eLazyBoolCalculate)
{
-#ifdef LLDB_CONFIGURATION_DEBUG
+#ifdef FOOBAR
std::string new_name(parent.GetName().AsCString());
new_name += "$$__synth__";
SetName (ConstString(new_name.c_str()));
#else
SetName(parent.GetName());
#endif
- CopyParentData();
+ CopyValueData(m_parent);
CreateSynthFilter();
}
@@ -181,8 +182,8 @@ ValueObjectSynthetic::UpdateValue ()
if (m_synth_filter_ap->Update() == false)
{
// filter said that cached values are stale
- m_children_byindex.clear();
- m_name_toindex.clear();
+ m_children_byindex.Clear();
+ m_name_toindex.Clear();
// usually, an object's value can change but this does not alter its children count
// for a synthetic VO that might indeed happen, so we need to tell the upper echelons
// that they need to come back to us asking for children
@@ -191,7 +192,20 @@ ValueObjectSynthetic::UpdateValue ()
m_might_have_children = eLazyBoolCalculate;
}
- CopyParentData();
+ m_provides_value = eLazyBoolCalculate;
+
+ lldb::ValueObjectSP synth_val(m_synth_filter_ap->GetSyntheticValue());
+
+ if (synth_val && synth_val->CanProvideValue())
+ {
+ m_provides_value = eLazyBoolYes;
+ CopyValueData(synth_val.get());
+ }
+ else
+ {
+ m_provides_value = eLazyBoolNo;
+ CopyValueData(m_parent);
+ }
SetValueIsValid(true);
return true;
@@ -202,23 +216,22 @@ ValueObjectSynthetic::GetChildAtIndex (size_t idx, bool can_create)
{
UpdateValueIfNeeded();
- ByIndexIterator iter = m_children_byindex.find(idx);
-
- if (iter == m_children_byindex.end())
+ ValueObject *valobj;
+ if (m_children_byindex.GetValueForKey(idx, valobj) == false)
{
if (can_create && m_synth_filter_ap.get() != NULL)
{
lldb::ValueObjectSP synth_guy = m_synth_filter_ap->GetChildAtIndex (idx);
if (!synth_guy)
return synth_guy;
- m_children_byindex[idx]= synth_guy.get();
+ m_children_byindex.SetValueForKey(idx, synth_guy.get());
return synth_guy;
}
else
return lldb::ValueObjectSP();
}
else
- return iter->second->GetSP();
+ return valobj->GetSP();
}
lldb::ValueObjectSP
@@ -239,20 +252,21 @@ ValueObjectSynthetic::GetIndexOfChildWithName (const ConstString &name)
{
UpdateValueIfNeeded();
- NameToIndexIterator iter = m_name_toindex.find(name.GetCString());
+ uint32_t found_index = UINT32_MAX;
+ bool did_find = m_name_toindex.GetValueForKey(name.GetCString(), found_index);
- if (iter == m_name_toindex.end() && m_synth_filter_ap.get() != NULL)
+ if (!did_find && m_synth_filter_ap.get() != NULL)
{
uint32_t index = m_synth_filter_ap->GetIndexOfChildWithName (name);
if (index == UINT32_MAX)
return index;
- m_name_toindex[name.GetCString()] = index;
+ m_name_toindex.SetValueForKey(name.GetCString(), index);
return index;
}
- else if (iter == m_name_toindex.end() && m_synth_filter_ap.get() == NULL)
+ else if (!did_find && m_synth_filter_ap.get() == NULL)
return UINT32_MAX;
else /*if (iter != m_name_toindex.end())*/
- return iter->second;
+ return found_index;
}
bool
@@ -268,9 +282,19 @@ ValueObjectSynthetic::GetNonSyntheticValue ()
}
void
-ValueObjectSynthetic::CopyParentData ()
+ValueObjectSynthetic::CopyValueData (ValueObject *source)
{
- m_value = m_parent->GetValue();
+ m_value = (source->UpdateValueIfNeeded(), source->GetValue());
ExecutionContext exe_ctx (GetExecutionContextRef());
m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
}
+
+bool
+ValueObjectSynthetic::CanProvideValue ()
+{
+ if (!UpdateValueIfNeeded())
+ return false;
+ if (m_provides_value == eLazyBoolYes)
+ return true;
+ return m_parent->CanProvideValue();
+}
diff --git a/source/Core/ValueObjectVariable.cpp b/source/Core/ValueObjectVariable.cpp
index 225dc02c8add..ab74a50e7cd5 100644
--- a/source/Core/ValueObjectVariable.cpp
+++ b/source/Core/ValueObjectVariable.cpp
@@ -171,14 +171,44 @@ ValueObjectVariable::UpdateValue ()
m_value.SetClangType(clang_type);
Value::ValueType value_type = m_value.GetValueType();
-
+
+ Process *process = exe_ctx.GetProcessPtr();
+ const bool process_is_alive = process && process->IsAlive();
+ const uint32_t type_info = clang_type.GetTypeInfo();
+ const bool is_pointer_or_ref = (type_info & (lldb::eTypeIsPointer | lldb::eTypeIsReference)) != 0;
+
switch (value_type)
{
case Value::eValueTypeFileAddress:
- SetAddressTypeOfChildren(eAddressTypeFile);
+ // If this type is a pointer, then its children will be considered load addresses
+ // if the pointer or reference is dereferenced, but only if the process is alive.
+ //
+ // There could be global variables like in the following code:
+ // struct LinkedListNode { Foo* foo; LinkedListNode* next; };
+ // Foo g_foo1;
+ // Foo g_foo2;
+ // LinkedListNode g_second_node = { &g_foo2, NULL };
+ // LinkedListNode g_first_node = { &g_foo1, &g_second_node };
+ //
+ // When we aren't running, we should be able to look at these variables using
+ // the "target variable" command. Children of the "g_first_node" always will
+ // be of the same address type as the parent. But children of the "next" member of
+ // LinkedListNode will become load addresses if we have a live process, or remain
+ // what a file address if it what a file address.
+ if (process_is_alive && is_pointer_or_ref)
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+ else
+ SetAddressTypeOfChildren(eAddressTypeFile);
break;
case Value::eValueTypeHostAddress:
- SetAddressTypeOfChildren(eAddressTypeHost);
+ // Same as above for load addresses, except children of pointer or refs are always
+ // load addresses. Host addresses are used to store freeze dried variables. If this
+ // type is a struct, the entire struct contents will be copied into the heap of the
+ // LLDB process, but we do not currrently follow any pointers.
+ if (is_pointer_or_ref)
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+ else
+ SetAddressTypeOfChildren(eAddressTypeHost);
break;
case Value::eValueTypeLoadAddress:
case Value::eValueTypeScalar:
@@ -209,8 +239,7 @@ ValueObjectVariable::UpdateValue ()
// Make sure this type has a value before we try and read it
// If we have a file address, convert it to a load address if we can.
- Process *process = exe_ctx.GetProcessPtr();
- if (value_type == Value::eValueTypeFileAddress && process && process->IsAlive())
+ if (value_type == Value::eValueTypeFileAddress && process_is_alive)
{
lldb::addr_t file_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
if (file_addr != LLDB_INVALID_ADDRESS)
@@ -234,7 +263,7 @@ ValueObjectVariable::UpdateValue ()
}
}
- if (GetClangType().IsAggregateType())
+ if (!CanProvideValue())
{
// this value object represents an aggregate type whose
// children have values, but this object does not. So we
@@ -248,6 +277,8 @@ ValueObjectVariable::UpdateValue ()
Value value(m_value);
value.SetContext(Value::eContextTypeVariable, variable);
m_error = value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get());
+
+ SetValueDidChange (value_type != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
}
break;
}
diff --git a/source/DataFormatters/CF.cpp b/source/DataFormatters/CF.cpp
index e131b68096fd..483419e5ac3f 100644
--- a/source/DataFormatters/CF.cpp
+++ b/source/DataFormatters/CF.cpp
@@ -26,7 +26,7 @@ using namespace lldb_private;
using namespace lldb_private::formatters;
bool
-lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
time_t epoch = GetOSXEpoch();
epoch = epoch + (time_t)valobj.GetValueAsUnsigned(0);
@@ -41,7 +41,7 @@ lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, St
}
bool
-lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -105,7 +105,7 @@ lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& str
}
bool
-lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -235,7 +235,7 @@ lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Strea
}
bool
-lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
diff --git a/source/DataFormatters/CXXFormatterFunctions.cpp b/source/DataFormatters/CXXFormatterFunctions.cpp
index ae5b35fd2b1c..04cdadf5a98f 100644
--- a/source/DataFormatters/CXXFormatterFunctions.cpp
+++ b/source/DataFormatters/CXXFormatterFunctions.cpp
@@ -10,6 +10,8 @@
#include "lldb/lldb-python.h"
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
+#include "lldb/DataFormatters/StringPrinter.h"
+#include "lldb/DataFormatters/TypeSummary.h"
#include "llvm/Support/ConvertUTF.h"
@@ -20,10 +22,16 @@
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ProcessStructReader.h"
+
#include <algorithm>
+#if __ANDROID_NDK__
+#include <sys/types.h>
+#endif
using namespace lldb;
using namespace lldb_private;
@@ -187,283 +195,53 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
return valobj_sp;
}
-// use this call if you already have an LLDB-side buffer for the data
-template<typename SourceDataType>
-static bool
-DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
- const SourceDataType*,
- UTF8**,
- UTF8*,
- ConversionFlags),
- DataExtractor& data,
- Stream& stream,
- char prefix_token = '@',
- char quote = '"',
- uint32_t sourceSize = 0)
+bool
+lldb_private::formatters::FunctionPointerSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
- if (prefix_token != 0)
- stream.Printf("%c",prefix_token);
- if (quote != 0)
- stream.Printf("%c",quote);
- if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd())
+ std::string destination;
+ StreamString sstr;
+ AddressType func_ptr_address_type = eAddressTypeInvalid;
+ addr_t func_ptr_address = valobj.GetPointerValue (&func_ptr_address_type);
+ if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS)
{
- const int bufferSPSize = data.GetByteSize();
- if (sourceSize == 0)
- {
- const int origin_encoding = 8*sizeof(SourceDataType);
- sourceSize = bufferSPSize/(origin_encoding / 4);
- }
-
- SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart();
- SourceDataType *data_end_ptr = data_ptr + sourceSize;
-
- while (data_ptr < data_end_ptr)
+ switch (func_ptr_address_type)
{
- if (!*data_ptr)
- {
- data_end_ptr = data_ptr;
+ case eAddressTypeInvalid:
+ case eAddressTypeFile:
+ case eAddressTypeHost:
break;
+
+ case eAddressTypeLoad:
+ {
+ ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
+
+ Address so_addr;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target && target->GetSectionLoadList().IsEmpty() == false)
+ {
+ if (target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address, so_addr))
+ {
+ so_addr.Dump (&sstr,
+ exe_ctx.GetBestExecutionContextScope(),
+ Address::DumpStyleResolvedDescription,
+ Address::DumpStyleSectionNameOffset);
+ }
+ }
}
- data_ptr++;
- }
-
- data_ptr = (SourceDataType*)data.GetDataStart();
-
- lldb::DataBufferSP utf8_data_buffer_sp;
- UTF8* utf8_data_ptr = nullptr;
- UTF8* utf8_data_end_ptr = nullptr;
-
- if (ConvertFunction)
- {
- 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 );
- utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr
- }
- else
- {
- // just copy the pointers - the cast is necessary to make the compiler happy
- // but this should only happen if we are reading UTF8 data
- utf8_data_ptr = (UTF8*)data_ptr;
- utf8_data_end_ptr = (UTF8*)data_end_ptr;
- }
-
- // since we tend to accept partial data (and even partially malformed data)
- // we might end up with no NULL terminator before the end_ptr
- // hence we need to take a slower route and ensure we stay within boundaries
- for (;utf8_data_ptr != utf8_data_end_ptr; utf8_data_ptr++)
- {
- if (!*utf8_data_ptr)
break;
- stream.Printf("%c",*utf8_data_ptr);
}
}
- if (quote != 0)
- stream.Printf("%c",quote);
- return true;
-}
-
-template<typename SourceDataType>
-class ReadUTFBufferAndDumpToStreamOptions
-{
-public:
- typedef ConversionResult (*ConvertFunctionType) (const SourceDataType**,
- const SourceDataType*,
- UTF8**,
- UTF8*,
- ConversionFlags);
-
- ReadUTFBufferAndDumpToStreamOptions () :
- m_conversion_function(NULL),
- m_location(0),
- m_process_sp(),
- m_stream(NULL),
- m_prefix_token('@'),
- m_quote('"'),
- m_source_size(0),
- m_needs_zero_termination(true)
- {
- }
-
- ReadUTFBufferAndDumpToStreamOptions&
- SetConversionFunction (ConvertFunctionType f)
- {
- m_conversion_function = f;
- return *this;
- }
-
- ConvertFunctionType
- GetConversionFunction () const
- {
- return m_conversion_function;
- }
-
- ReadUTFBufferAndDumpToStreamOptions&
- SetLocation (uint64_t l)
- {
- m_location = l;
- return *this;
- }
-
- uint64_t
- GetLocation () const
- {
- return m_location;
- }
-
- ReadUTFBufferAndDumpToStreamOptions&
- SetProcessSP (ProcessSP p)
- {
- m_process_sp = p;
- return *this;
- }
-
- ProcessSP
- GetProcessSP () const
- {
- return m_process_sp;
- }
-
- ReadUTFBufferAndDumpToStreamOptions&
- SetStream (Stream* s)
- {
- m_stream = s;
- return *this;
- }
-
- Stream*
- GetStream () const
- {
- return m_stream;
- }
-
- ReadUTFBufferAndDumpToStreamOptions&
- SetPrefixToken (char p)
- {
- m_prefix_token = p;
- return *this;
- }
-
- char
- GetPrefixToken () const
- {
- return m_prefix_token;
- }
-
- ReadUTFBufferAndDumpToStreamOptions&
- SetQuote (char q)
- {
- m_quote = q;
- return *this;
- }
-
- char
- GetQuote () const
- {
- return m_quote;
- }
-
- ReadUTFBufferAndDumpToStreamOptions&
- SetSourceSize (uint32_t s)
- {
- m_source_size = s;
- return *this;
- }
-
- uint32_t
- GetSourceSize () const
- {
- return m_source_size;
- }
-
- ReadUTFBufferAndDumpToStreamOptions&
- SetNeedsZeroTermination (bool z)
+ if (sstr.GetSize() > 0)
{
- m_needs_zero_termination = z;
- return *this;
- }
-
- bool
- GetNeedsZeroTermination () const
- {
- return m_needs_zero_termination;
- }
-
-private:
- ConvertFunctionType m_conversion_function;
- uint64_t m_location;
- ProcessSP m_process_sp;
- Stream* m_stream;
- char m_prefix_token;
- char m_quote;
- uint32_t m_source_size;
- bool m_needs_zero_termination;
-};
-
-template<typename SourceDataType>
-static bool
-ReadUTFBufferAndDumpToStream (const ReadUTFBufferAndDumpToStreamOptions<SourceDataType>& options)
-{
- if (options.GetLocation() == 0 || options.GetLocation() == LLDB_INVALID_ADDRESS)
- return false;
-
- ProcessSP process_sp(options.GetProcessSP());
-
- if (!process_sp)
- return false;
-
- const int type_width = sizeof(SourceDataType);
- const int origin_encoding = 8 * type_width ;
- if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
- return false;
- // if not UTF8, I need a conversion function to return proper UTF8
- if (origin_encoding != 8 && !options.GetConversionFunction())
- return false;
-
- if (!options.GetStream())
- return false;
-
- uint32_t sourceSize = options.GetSourceSize();
- bool needs_zero_terminator = options.GetNeedsZeroTermination();
-
- if (!sourceSize)
- {
- sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
- needs_zero_terminator = true;
+ stream.Printf("(%s)", sstr.GetData());
+ return true;
}
else
- sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary());
-
- const int bufferSPSize = sourceSize * type_width;
-
- lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
-
- if (!buffer_sp->GetBytes())
return false;
-
- 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);
- else
- data_read = process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error);
-
- if (error.Fail() || data_read == 0)
- {
- options.GetStream()->Printf("unable to read data");
- return true;
- }
-
- DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
-
- return DumpUTFBufferToStream(options.GetConversionFunction(), data, *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), sourceSize);
}
bool
-lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -474,14 +252,13 @@ lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stre
if (!valobj_addr)
return false;
- ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
+ ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(valobj_addr);
- options.SetConversionFunction(ConvertUTF16toUTF8);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetPrefixToken('u');
- if (!ReadUTFBufferAndDumpToStream(options))
+ if (!ReadStringAndDumpToStream<StringElementType::UTF16>(options))
{
stream.Printf("Summary Unavailable");
return true;
@@ -491,7 +268,7 @@ lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stre
}
bool
-lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -502,14 +279,13 @@ lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stre
if (!valobj_addr)
return false;
- ReadUTFBufferAndDumpToStreamOptions<UTF32> options;
+ ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(valobj_addr);
- options.SetConversionFunction(ConvertUTF32toUTF8);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetPrefixToken('U');
- if (!ReadUTFBufferAndDumpToStream(options))
+ if (!ReadStringAndDumpToStream<StringElementType::UTF32>(options))
{
stream.Printf("Summary Unavailable");
return true;
@@ -519,7 +295,7 @@ lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stre
}
bool
-lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -543,45 +319,20 @@ lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Strea
ClangASTType wchar_clang_type = ClangASTContext::GetBasicType(ast, lldb::eBasicTypeWChar);
const uint32_t wchar_size = wchar_clang_type.GetBitSize();
+ ReadStringAndDumpToStreamOptions options(valobj);
+ options.SetLocation(data_addr);
+ options.SetProcessSP(process_sp);
+ options.SetStream(&stream);
+ options.SetPrefixToken('L');
+
switch (wchar_size)
{
case 8:
- {
- // utf 8
-
- ReadUTFBufferAndDumpToStreamOptions<UTF8> options;
- options.SetLocation(data_addr);
- options.SetConversionFunction(nullptr);
- options.SetProcessSP(process_sp);
- options.SetStream(&stream);
- options.SetPrefixToken('L');
-
- return ReadUTFBufferAndDumpToStream(options);
- }
+ return ReadStringAndDumpToStream<StringElementType::UTF8>(options);
case 16:
- {
- // utf 16
- ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
- options.SetLocation(data_addr);
- options.SetConversionFunction(ConvertUTF16toUTF8);
- options.SetProcessSP(process_sp);
- options.SetStream(&stream);
- options.SetPrefixToken('L');
-
- return ReadUTFBufferAndDumpToStream(options);
- }
+ return ReadStringAndDumpToStream<StringElementType::UTF16>(options);
case 32:
- {
- // utf 32
- ReadUTFBufferAndDumpToStreamOptions<UTF32> options;
- options.SetLocation(data_addr);
- options.SetConversionFunction(ConvertUTF32toUTF8);
- options.SetProcessSP(process_sp);
- options.SetStream(&stream);
- options.SetPrefixToken('L');
-
- return ReadUTFBufferAndDumpToStream(options);
- }
+ return ReadStringAndDumpToStream<StringElementType::UTF32>(options);
default:
stream.Printf("size for wchar_t is not valid");
return true;
@@ -590,7 +341,7 @@ lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Strea
}
bool
-lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&)
{
DataExtractor data;
Error error;
@@ -604,11 +355,18 @@ lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& st
if (!value.empty())
stream.Printf("%s ", value.c_str());
- return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1);
+ ReadBufferAndDumpToStreamOptions options(valobj);
+ options.SetData(data);
+ options.SetStream(&stream);
+ options.SetPrefixToken('u');
+ options.SetQuote('\'');
+ options.SetSourceSize(1);
+
+ return ReadBufferAndDumpToStream<StringElementType::UTF16>(options);
}
bool
-lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&)
{
DataExtractor data;
Error error;
@@ -622,11 +380,18 @@ lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& st
if (!value.empty())
stream.Printf("%s ", value.c_str());
- return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1);
+ ReadBufferAndDumpToStreamOptions options(valobj);
+ options.SetData(data);
+ options.SetStream(&stream);
+ options.SetPrefixToken('U');
+ options.SetQuote('\'');
+ options.SetSourceSize(1);
+
+ return ReadBufferAndDumpToStream<StringElementType::UTF32>(options);
}
bool
-lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&)
{
DataExtractor data;
Error error;
@@ -635,55 +400,14 @@ lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& str
if (error.Fail())
return false;
- clang::ASTContext* ast = valobj.GetClangType().GetASTContext();
-
- if (!ast)
- return false;
-
- ClangASTType wchar_clang_type = ClangASTContext::GetBasicType(ast, lldb::eBasicTypeWChar);
- const uint32_t wchar_size = wchar_clang_type.GetBitSize();
- std::string value;
+ ReadBufferAndDumpToStreamOptions options(valobj);
+ options.SetData(data);
+ options.SetStream(&stream);
+ options.SetPrefixToken('L');
+ options.SetQuote('\'');
+ options.SetSourceSize(1);
- switch (wchar_size)
- {
- case 8:
- // utf 8
- valobj.GetValueAsCString(lldb::eFormatChar, value);
- if (!value.empty())
- stream.Printf("%s ", value.c_str());
- return DumpUTFBufferToStream<UTF8>(nullptr,
- data,
- stream,
- 'L',
- '\'',
- 1);
- case 16:
- // utf 16
- valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
- if (!value.empty())
- stream.Printf("%s ", value.c_str());
- return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,
- data,
- stream,
- 'L',
- '\'',
- 1);
- case 32:
- // utf 32
- valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
- if (!value.empty())
- stream.Printf("%s ", value.c_str());
- return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,
- data,
- stream,
- 'L',
- '\'',
- 1);
- default:
- stream.Printf("size for wchar_t is not valid");
- return true;
- }
- return true;
+ return ReadBufferAndDumpToStream<StringElementType::UTF16>(options);
}
// the field layout in a libc++ string (cap, side, data or data, size, cap)
@@ -769,7 +493,7 @@ ExtractLibcxxStringInfo (ValueObject& valobj,
}
bool
-lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
uint64_t size = 0;
ValueObjectSP location_sp((ValueObject*)nullptr);
@@ -782,34 +506,45 @@ lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Str
}
if (!location_sp)
return false;
- return WCharStringSummaryProvider(*location_sp.get(), stream);
+ return WCharStringSummaryProvider(*location_sp.get(), stream, options);
}
bool
-lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& summary_options)
{
uint64_t size = 0;
ValueObjectSP location_sp((ValueObject*)nullptr);
+
if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
return false;
+
if (size == 0)
{
stream.Printf("\"\"");
return true;
}
+
if (!location_sp)
return false;
- Error error;
- if (location_sp->ReadPointedString(stream,
- error,
- 0, // max length is decided by the settings
- false) == 0) // do not honor array (terminates on first 0 byte even for a char[])
- stream.Printf("\"\""); // if nothing was read, print an empty string
- return error.Success();
+
+ DataExtractor extractor;
+ if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped)
+ size = std::min<decltype(size)>(size, valobj.GetTargetSP()->GetMaximumSizeOfStringSummary());
+ location_sp->GetPointeeData(extractor, 0, size);
+
+ ReadBufferAndDumpToStreamOptions options(valobj);
+ options.SetData(extractor); // none of this matters for a string - pass some defaults
+ options.SetStream(&stream);
+ options.SetPrefixToken(0);
+ options.SetQuote('"');
+ options.SetSourceSize(size);
+ lldb_private::formatters::ReadBufferAndDumpToStream<lldb_private::formatters::StringElementType::ASCII>(options);
+
+ return true;
}
bool
-lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -886,7 +621,7 @@ lldb_private::formatters::ObjCClassSyntheticFrontEndCreator (CXXSyntheticChildre
template<bool needs_at>
bool
-lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -1037,8 +772,28 @@ lldb_private::formatters::NSTaggedString_SummaryProvider (ObjCLanguageRuntime::C
return true;
}
+static ClangASTType
+GetNSPathStore2Type (Target &target)
+{
+ static ConstString g_type_name("__lldb_autogen_nspathstore2");
+
+ ClangASTContext *ast_ctx = target.GetScratchClangASTContext();
+
+ if (!ast_ctx)
+ return ClangASTType();
+
+ ClangASTType voidstar = ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType();
+ ClangASTType uint32 = ast_ctx->GetIntTypeFromBitSize(32, false);
+
+ return ast_ctx->GetOrCreateStructForIdentifier(g_type_name, {
+ {"isa",voidstar},
+ {"lengthAndRef",uint32},
+ {"buffer",voidstar}
+ });
+}
+
bool
-lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& summary_options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -1131,8 +886,7 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
return false;
if (has_explicit_length && is_unicode)
{
- ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
- options.SetConversionFunction(ConvertUTF16toUTF8);
+ ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
@@ -1140,10 +894,21 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(false);
- return ReadUTFBufferAndDumpToStream (options);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
+ return ReadStringAndDumpToStream<StringElementType::UTF16>(options);
}
else
- return ReadAsciiBufferAndDumpToStream(location+1,process_sp,stream, explicit_length);
+ {
+ ReadStringAndDumpToStreamOptions options(valobj);
+ options.SetLocation(location+1);
+ options.SetProcessSP(process_sp);
+ options.SetStream(&stream);
+ options.SetPrefixToken('@');
+ options.SetSourceSize(explicit_length);
+ options.SetNeedsZeroTermination(false);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
+ return ReadStringAndDumpToStream<StringElementType::ASCII>(options);
+ }
}
else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable)
{
@@ -1169,8 +934,7 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
if (error.Fail())
return false;
}
- ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
- options.SetConversionFunction(ConvertUTF16toUTF8);
+ ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
@@ -1178,13 +942,16 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(has_explicit_length == false);
- return ReadUTFBufferAndDumpToStream (options);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
+ return ReadStringAndDumpToStream<StringElementType::UTF16> (options);
}
else if (is_special)
{
- uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8);
- ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
- options.SetConversionFunction(ConvertUTF16toUTF8);
+ ProcessStructReader reader(valobj.GetProcessSP().get(), valobj.GetValueAsUnsigned(0), GetNSPathStore2Type(*valobj.GetTargetSP()));
+ explicit_length = reader.GetField<uint32_t>(ConstString("lengthAndRef")) >> 20;
+ lldb::addr_t location = valobj.GetValueAsUnsigned(0) + ptr_size + 4;
+
+ ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
@@ -1192,14 +959,22 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(has_explicit_length == false);
- return ReadUTFBufferAndDumpToStream (options);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
+ return ReadStringAndDumpToStream<StringElementType::UTF16> (options);
}
else if (is_inline)
{
uint64_t location = valobj_addr + 2*ptr_size;
if (!has_explicit_length)
location++;
- return ReadAsciiBufferAndDumpToStream(location,process_sp,stream,explicit_length);
+ ReadStringAndDumpToStreamOptions options(valobj);
+ options.SetLocation(location);
+ options.SetProcessSP(process_sp);
+ options.SetStream(&stream);
+ options.SetPrefixToken('@');
+ options.SetSourceSize(explicit_length);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
+ return ReadStringAndDumpToStream<StringElementType::ASCII>(options);
}
else
{
@@ -1209,16 +984,19 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
return false;
if (has_explicit_length && !has_null)
explicit_length++; // account for the fact that there is no NULL and we need to have one added
- return ReadAsciiBufferAndDumpToStream(location,process_sp,stream,explicit_length);
+ ReadStringAndDumpToStreamOptions options(valobj);
+ options.SetLocation(location);
+ options.SetProcessSP(process_sp);
+ options.SetPrefixToken('@');
+ options.SetStream(&stream);
+ options.SetSourceSize(explicit_length);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
+ return ReadStringAndDumpToStream<StringElementType::ASCII>(options);
}
-
- stream.Printf("class name = %s",class_name);
- return true;
-
}
bool
-lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
TargetSP target_sp(valobj.GetTargetSP());
if (!target_sp)
@@ -1241,38 +1019,38 @@ lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj
ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type));
child_sp->GetValueAsUnsigned(0);
if (child_sp)
- return NSStringSummaryProvider(*child_sp, stream);
+ return NSStringSummaryProvider(*child_sp, stream, options);
return false;
}
bool
-lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
- return NSAttributedStringSummaryProvider(valobj, stream);
+ return NSAttributedStringSummaryProvider(valobj, stream, options);
}
bool
-lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
stream.Printf("%s",valobj.GetObjectDescription());
return true;
}
bool
-lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
const uint32_t type_info = valobj.GetClangType().GetTypeInfo();
ValueObjectSP real_guy_sp = valobj.GetSP();
- if (type_info & ClangASTType::eTypeIsPointer)
+ if (type_info & eTypeIsPointer)
{
Error err;
real_guy_sp = valobj.Dereference(err);
if (err.Fail() || !real_guy_sp)
return false;
}
- else if (type_info & ClangASTType::eTypeIsReference)
+ else if (type_info & eTypeIsReference)
{
real_guy_sp = valobj.GetChildAtIndex(0, true);
if (!real_guy_sp)
@@ -1290,7 +1068,7 @@ lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream&
template <bool is_sel_ptr>
bool
-lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
lldb::ValueObjectSP valobj_sp;
@@ -1398,7 +1176,7 @@ lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update()
return false;
Error err;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
- m_item_sp = ValueObject::CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, item_ptr->GetClangType().GetPointeeType());
+ m_item_sp = CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, item_ptr->GetClangType().GetPointeeType());
if (err.Fail())
m_item_sp.reset();
return false;
@@ -1437,13 +1215,13 @@ lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSynthe
}
template bool
-lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ;
+lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
template bool
-lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ;
+lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
template bool
-lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ;
+lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
template bool
-lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ;
+lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
diff --git a/source/DataFormatters/Cocoa.cpp b/source/DataFormatters/Cocoa.cpp
index 8e92de4ddaa4..137fd4f483cc 100644
--- a/source/DataFormatters/Cocoa.cpp
+++ b/source/DataFormatters/Cocoa.cpp
@@ -26,7 +26,7 @@ using namespace lldb_private;
using namespace lldb_private::formatters;
bool
-lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -60,7 +60,7 @@ lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream&
ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true));
StreamString summary_stream;
- bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
+ bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
if (was_nsstring_ok && summary_stream.GetSize() > 0)
{
stream.Printf("%s",summary_stream.GetData());
@@ -73,7 +73,7 @@ lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream&
}
bool
-lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -106,7 +106,7 @@ lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream
uint64_t offset = ptr_size;
ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true));
StreamString summary_stream;
- bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
+ bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
if (was_nsstring_ok && summary_stream.GetSize() > 0)
{
stream.Printf("%s",summary_stream.GetData());
@@ -117,7 +117,7 @@ lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream
}
bool
-lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -150,7 +150,7 @@ lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, St
uint64_t offset = ptr_size;
ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true));
StreamString summary_stream;
- bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
+ bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
if (was_nsstring_ok && summary_stream.GetSize() > 0)
{
stream.Printf("%s",summary_stream.GetData());
@@ -163,7 +163,7 @@ lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, St
}
bool
-lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -212,7 +212,7 @@ lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream
}
bool
-lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -290,7 +290,7 @@ lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream
}
bool
-lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -413,7 +413,7 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream&
}
bool
-lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -453,7 +453,7 @@ lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& str
if (text->GetValueAsUnsigned(0) == 0)
return false;
StreamString summary;
- if (!NSStringSummaryProvider(*text, summary))
+ if (!NSStringSummaryProvider(*text, summary, options))
return false;
if (base && base->GetValueAsUnsigned(0))
{
@@ -461,7 +461,7 @@ lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& str
summary.GetString().resize(summary.GetSize()-1);
summary.Printf(" -- ");
StreamString base_summary;
- if (NSURLSummaryProvider(*base, base_summary) && base_summary.GetSize() > 0)
+ if (NSURLSummaryProvider(*base, base_summary, options) && base_summary.GetSize() > 0)
summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData());
}
if (summary.GetSize())
@@ -478,7 +478,7 @@ lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& str
}
bool
-lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -552,7 +552,7 @@ lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& st
// vendor decides to get creative
time_t epoch = GetOSXEpoch();
epoch = epoch + (time_t)date_value;
- tm *tm_date = localtime(&epoch);
+ tm *tm_date = gmtime(&epoch);
if (!tm_date)
return false;
std::string buffer(1024,0);
diff --git a/source/DataFormatters/DataVisualization.cpp b/source/DataFormatters/DataVisualization.cpp
index c2c2206f3449..7ef0be50efe0 100644
--- a/source/DataFormatters/DataVisualization.cpp
+++ b/source/DataFormatters/DataVisualization.cpp
@@ -101,6 +101,18 @@ DataVisualization::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp)
}
#endif
+lldb::TypeValidatorImplSP
+DataVisualization::GetValidator (ValueObject& valobj, lldb::DynamicValueType use_dynamic)
+{
+ return GetFormatManager().GetValidator(valobj, use_dynamic);
+}
+
+lldb::TypeValidatorImplSP
+DataVisualization::GetValidatorForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ return GetFormatManager().GetValidatorForType(type_sp);
+}
+
bool
DataVisualization::AnyMatches (ConstString type_name,
TypeCategoryImpl::FormatCategoryItems items,
@@ -184,6 +196,18 @@ DataVisualization::Categories::Disable (const lldb::TypeCategoryImplSP& category
}
void
+DataVisualization::Categories::EnableStar ()
+{
+ GetFormatManager().EnableAllCategories ();
+}
+
+void
+DataVisualization::Categories::DisableStar ()
+{
+ GetFormatManager().DisableAllCategories();
+}
+
+void
DataVisualization::Categories::LoopThrough (FormatManager::CategoryCallback callback, void* callback_baton)
{
GetFormatManager().LoopThroughCategories(callback, callback_baton);
diff --git a/source/DataFormatters/FormatCache.cpp b/source/DataFormatters/FormatCache.cpp
index 3721f182f91e..aaa4bc1f958a 100644
--- a/source/DataFormatters/FormatCache.cpp
+++ b/source/DataFormatters/FormatCache.cpp
@@ -25,16 +25,20 @@ FormatCache::Entry::Entry () :
m_format_cached(false),
m_summary_cached(false),
m_synthetic_cached(false),
+m_validator_cached(false),
m_format_sp(),
m_summary_sp(),
-m_synthetic_sp()
+m_synthetic_sp(),
+m_validator_sp()
{}
FormatCache::Entry::Entry (lldb::TypeFormatImplSP format_sp) :
m_summary_cached(false),
m_synthetic_cached(false),
+m_validator_cached(false),
m_summary_sp(),
-m_synthetic_sp()
+m_synthetic_sp(),
+m_validator_sp()
{
SetFormat (format_sp);
}
@@ -42,8 +46,10 @@ m_synthetic_sp()
FormatCache::Entry::Entry (lldb::TypeSummaryImplSP summary_sp) :
m_format_cached(false),
m_synthetic_cached(false),
+m_validator_cached(false),
m_format_sp(),
-m_synthetic_sp()
+m_synthetic_sp(),
+m_validator_sp()
{
SetSummary (summary_sp);
}
@@ -51,17 +57,31 @@ m_synthetic_sp()
FormatCache::Entry::Entry (lldb::SyntheticChildrenSP synthetic_sp) :
m_format_cached(false),
m_summary_cached(false),
+m_validator_cached(false),
m_format_sp(),
-m_summary_sp()
+m_summary_sp(),
+m_validator_sp()
{
SetSynthetic (synthetic_sp);
}
-FormatCache::Entry::Entry (lldb::TypeFormatImplSP format_sp, lldb::TypeSummaryImplSP summary_sp, lldb::SyntheticChildrenSP synthetic_sp)
+FormatCache::Entry::Entry (lldb::TypeValidatorImplSP validator_sp) :
+m_format_cached(false),
+m_summary_cached(false),
+m_synthetic_cached(false),
+m_format_sp(),
+m_summary_sp(),
+m_synthetic_sp()
+{
+ SetValidator (validator_sp);
+}
+
+FormatCache::Entry::Entry (lldb::TypeFormatImplSP format_sp, lldb::TypeSummaryImplSP summary_sp, lldb::SyntheticChildrenSP synthetic_sp, lldb::TypeValidatorImplSP validator_sp)
{
SetFormat (format_sp);
SetSummary (summary_sp);
SetSynthetic (synthetic_sp);
+ SetValidator (validator_sp);
}
bool
@@ -82,6 +102,12 @@ FormatCache::Entry::IsSyntheticCached ()
return m_synthetic_cached;
}
+bool
+FormatCache::Entry::IsValidatorCached ()
+{
+ return m_validator_cached;
+}
+
lldb::TypeFormatImplSP
FormatCache::Entry::GetFormat ()
{
@@ -100,6 +126,12 @@ FormatCache::Entry::GetSynthetic ()
return m_synthetic_sp;
}
+lldb::TypeValidatorImplSP
+FormatCache::Entry::GetValidator ()
+{
+ return m_validator_sp;
+}
+
void
FormatCache::Entry::SetFormat (lldb::TypeFormatImplSP format_sp)
{
@@ -121,6 +153,13 @@ FormatCache::Entry::SetSynthetic (lldb::SyntheticChildrenSP synthetic_sp)
m_synthetic_sp = synthetic_sp;
}
+void
+FormatCache::Entry::SetValidator (lldb::TypeValidatorImplSP validator_sp)
+{
+ m_validator_cached = true;
+ m_validator_sp = validator_sp;
+}
+
FormatCache::FormatCache () :
m_map(),
m_mutex (Mutex::eMutexTypeRecursive)
@@ -201,6 +240,26 @@ FormatCache::GetSynthetic (const ConstString& type,lldb::SyntheticChildrenSP& sy
return false;
}
+bool
+FormatCache::GetValidator (const ConstString& type,lldb::TypeValidatorImplSP& validator_sp)
+{
+ Mutex::Locker lock(m_mutex);
+ auto entry = GetEntry(type);
+ if (entry.IsValidatorCached())
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ m_cache_hits++;
+#endif
+ validator_sp = entry.GetValidator();
+ return true;
+ }
+#ifdef LLDB_CONFIGURATION_DEBUG
+ m_cache_misses++;
+#endif
+ validator_sp.reset();
+ return false;
+}
+
void
FormatCache::SetFormat (const ConstString& type,lldb::TypeFormatImplSP& format_sp)
{
@@ -223,6 +282,13 @@ FormatCache::SetSynthetic (const ConstString& type,lldb::SyntheticChildrenSP& sy
}
void
+FormatCache::SetValidator (const ConstString& type,lldb::TypeValidatorImplSP& validator_sp)
+{
+ Mutex::Locker lock(m_mutex);
+ GetEntry(type).SetValidator(validator_sp);
+}
+
+void
FormatCache::Clear ()
{
Mutex::Locker lock(m_mutex);
diff --git a/source/DataFormatters/FormatManager.cpp b/source/DataFormatters/FormatManager.cpp
index 28d108f2410a..01799cef5e4e 100644
--- a/source/DataFormatters/FormatManager.cpp
+++ b/source/DataFormatters/FormatManager.cpp
@@ -447,6 +447,32 @@ FormatManager::GetSyntheticChildrenForType (lldb::TypeNameSpecifierImplSP type_s
}
#endif
+lldb::TypeValidatorImplSP
+FormatManager::GetValidatorForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ if (!type_sp)
+ return lldb::TypeValidatorImplSP();
+ lldb::TypeValidatorImplSP validator_chosen_sp;
+ uint32_t num_categories = m_categories_map.GetCount();
+ lldb::TypeCategoryImplSP category_sp;
+ uint32_t prio_category = UINT32_MAX;
+ for (uint32_t category_id = 0;
+ category_id < num_categories;
+ category_id++)
+ {
+ category_sp = GetCategoryAtIndex(category_id);
+ if (category_sp->IsEnabled() == false)
+ continue;
+ lldb::TypeValidatorImplSP validator_current_sp(category_sp->GetValidatorForType(type_sp).get());
+ if (validator_current_sp && (validator_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition())))
+ {
+ prio_category = category_sp->GetEnabledPosition();
+ validator_chosen_sp = validator_current_sp;
+ }
+ }
+ return validator_chosen_sp;
+}
+
lldb::TypeCategoryImplSP
FormatManager::GetCategory (const ConstString& category_name,
bool can_create)
@@ -501,10 +527,9 @@ FormatManager::ShouldPrintAsOneLiner (ValueObject& valobj)
if (valobj.GetTargetSP().get() && valobj.GetTargetSP()->GetDebugger().GetAutoOneLineSummaries() == false)
return false; // then don't oneline
- // if this object has a summary, don't try to do anything special to it
- // if the user wants one-liner, they can ask for it in summary :)
+ // if this object has a summary, then ask the summary
if (valobj.GetSummaryFormat().get() != nullptr)
- return false;
+ return valobj.GetSummaryFormat()->IsOneLiner();
// no children, no party
if (valobj.GetNumChildren() == 0)
@@ -516,6 +541,7 @@ FormatManager::ShouldPrintAsOneLiner (ValueObject& valobj)
idx < valobj.GetNumChildren();
idx++)
{
+ bool is_synth_val = false;
ValueObjectSP child_sp(valobj.GetChildAtIndex(idx, true));
// something is wrong here - bail out
if (!child_sp)
@@ -523,7 +549,17 @@ FormatManager::ShouldPrintAsOneLiner (ValueObject& valobj)
// if we decided to define synthetic children for a type, we probably care enough
// to show them, but avoid nesting children in children
if (child_sp->GetSyntheticChildren().get() != nullptr)
- return false;
+ {
+ ValueObjectSP synth_sp(child_sp->GetSyntheticValue());
+ // wait.. wat? just get out of here..
+ if (!synth_sp)
+ return false;
+ // but if we only have them to provide a value, keep going
+ if (synth_sp->MightHaveChildren() == false && synth_sp->DoesProvideSyntheticValue())
+ is_synth_val = true;
+ else
+ return false;
+ }
total_children_name_len += child_sp->GetName().GetLength();
@@ -547,7 +583,7 @@ FormatManager::ShouldPrintAsOneLiner (ValueObject& valobj)
// ...and no summary...
// (if it had a summary and the summary wanted children, we would have bailed out anyway
// so this only makes us bail out if this has no summary and we would then print children)
- if (!child_sp->GetSummaryFormat())
+ if (!child_sp->GetSummaryFormat() && !is_synth_val) // but again only do that if not a synthetic valued child
return false; // then bail out
}
}
@@ -756,6 +792,63 @@ FormatManager::GetSyntheticChildren (ValueObject& valobj,
}
#endif
+lldb::TypeValidatorImplSP
+FormatManager::GetValidator (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
+{
+ TypeValidatorImplSP retval;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+ ConstString valobj_type(GetTypeForCache(valobj, use_dynamic));
+ if (valobj_type)
+ {
+ if (log)
+ log->Printf("\n\n[FormatManager::GetValidator] Looking into cache for type %s", valobj_type.AsCString("<invalid>"));
+ if (m_format_cache.GetValidator(valobj_type,retval))
+ {
+ if (log)
+ {
+ log->Printf("[FormatManager::GetValidator] Cache search success. Returning.");
+ if (log->GetDebug())
+ log->Printf("[FormatManager::GetValidator] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ }
+ return retval;
+ }
+ if (log)
+ log->Printf("[FormatManager::GetValidator] Cache search failed. Going normal route");
+ }
+ retval = m_categories_map.GetValidator(valobj, use_dynamic);
+ if (!retval)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetValidator] Search failed. Giving hardcoded a chance.");
+ retval = GetHardcodedValidator(valobj, use_dynamic);
+ }
+ else if (valobj_type)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetValidator] Caching %p for type %s",
+ static_cast<void*>(retval.get()),
+ valobj_type.AsCString("<invalid>"));
+ m_format_cache.SetValidator(valobj_type,retval);
+ }
+ if (log && log->GetDebug())
+ log->Printf("[FormatManager::GetValidator] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ return retval;
+}
+
+lldb::TypeValidatorImplSP
+FormatManager::GetHardcodedValidator (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
+{
+ for (const auto& candidate: m_hardcoded_validators)
+ {
+ auto result = candidate(valobj,use_dynamic,*this);
+ if (result)
+ return result;
+ }
+ return nullptr;
+}
+
FormatManager::FormatManager() :
m_format_cache(),
m_named_summaries_map(this),
@@ -773,7 +866,8 @@ FormatManager::FormatManager() :
m_appkit_category_name(ConstString("AppKit")),
m_hardcoded_formats(),
m_hardcoded_summaries(),
- m_hardcoded_synthetics()
+ m_hardcoded_synthetics(),
+ m_hardcoded_validators()
{
LoadSystemFormatters();
@@ -825,6 +919,21 @@ AddStringSummary(TypeCategoryImpl::SharedPointer category_sp,
category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp);
}
+static void
+AddOneLineSummary (TypeCategoryImpl::SharedPointer category_sp,
+ ConstString type_name,
+ TypeSummaryImpl::Flags flags,
+ bool regex = false)
+{
+ flags.SetShowMembersOneLiner(true);
+ lldb::TypeSummaryImplSP summary_sp(new StringSummaryFormat(flags, ""));
+
+ if (regex)
+ category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp);
+ else
+ category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp);
+}
+
#ifndef LLDB_DISABLE_PYTHON
static void
AddCXXSummary (TypeCategoryImpl::SharedPointer category_sp,
@@ -945,13 +1054,6 @@ FormatManager::LoadLibStdcppFormatters()
AddCXXSynthetic(gnu_category_sp, lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true);
AddCXXSynthetic(gnu_category_sp, lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true);
-
- gnu_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::vector<std::allocator<bool> >"),
- TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
-
- gnu_category_sp->GetTypeSyntheticsContainer()->Add(ConstString("std::vector<std::allocator<bool> >"),
- SyntheticChildrenSP(new CXXSyntheticChildren(stl_synth_flags,"libc++ std::vector<bool> synthetic children",lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEndCreator)));
-
#endif
}
@@ -998,6 +1100,7 @@ FormatManager::LoadLibcxxFormatters()
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multiset synthetic children", ConstString("^std::__1::multiset<.+> >(( )?&)?$"), stl_synth_flags, true);
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multimap synthetic children", ConstString("^std::__1::multimap<.+> >(( )?&)?$"), stl_synth_flags, true);
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator, "libc++ std::unordered containers synthetic children", ConstString("^(std::__1::)unordered_(multi)?(map|set)<.+> >$"), stl_synth_flags, true);
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator, "libc++ std::initializer_list synthetic children", ConstString("^std::initializer_list<.+>(( )?&)?$"), stl_synth_flags, true);
libcxx_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)deque<.+>(( )?&)?$")),
SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
@@ -1124,6 +1227,10 @@ FormatManager::LoadObjCFormatters()
.SetHideItemNames(false);
TypeCategoryImpl::SharedPointer objc_category_sp = GetCategory(m_objc_category_name);
+ TypeCategoryImpl::SharedPointer appkit_category_sp = GetCategory(m_appkit_category_name);
+ TypeCategoryImpl::SharedPointer corefoundation_category_sp = GetCategory(m_corefoundation_category_name);
+ TypeCategoryImpl::SharedPointer coregraphics_category_sp = GetCategory(m_coregraphics_category_name);
+ TypeCategoryImpl::SharedPointer coreservices_category_sp = GetCategory(m_coreservices_category_name);
lldb::TypeSummaryImplSP ObjC_BOOL_summary(new CXXFunctionSummaryFormat(objc_flags, lldb_private::formatters::ObjCBOOLSummaryProvider,""));
objc_category_sp->GetTypeSummariesContainer()->Add(ConstString("BOOL"),
@@ -1159,8 +1266,6 @@ FormatManager::LoadObjCFormatters()
ConstString("__block_literal_generic"),
objc_flags);
- TypeCategoryImpl::SharedPointer corefoundation_category_sp = GetCategory(m_corefoundation_category_name);
-
AddStringSummary(corefoundation_category_sp,
"${var.years} years, ${var.months} months, ${var.days} days, ${var.hours} hours, ${var.minutes} minutes ${var.seconds} seconds",
ConstString("CFGregorianUnits"),
@@ -1169,43 +1274,35 @@ FormatManager::LoadObjCFormatters()
"location=${var.location} length=${var.length}",
ConstString("CFRange"),
objc_flags);
- AddStringSummary(corefoundation_category_sp,
- "(x=${var.x}, y=${var.y})",
- ConstString("NSPoint"),
- objc_flags);
- AddStringSummary(corefoundation_category_sp,
+
+ AddStringSummary(appkit_category_sp,
"location=${var.location}, length=${var.length}",
ConstString("NSRange"),
objc_flags);
- AddStringSummary(corefoundation_category_sp,
- "${var.origin}, ${var.size}",
- ConstString("NSRect"),
- objc_flags);
- AddStringSummary(corefoundation_category_sp,
+ AddStringSummary(appkit_category_sp,
"(${var.origin}, ${var.size}), ...",
ConstString("NSRectArray"),
objc_flags);
- AddStringSummary(objc_category_sp,
- "(width=${var.width}, height=${var.height})",
- ConstString("NSSize"),
- objc_flags);
-
- TypeCategoryImpl::SharedPointer coregraphics_category_sp = GetCategory(m_coregraphics_category_name);
-
- AddStringSummary(coregraphics_category_sp,
- "(width=${var.width}, height=${var.height})",
- ConstString("CGSize"),
- objc_flags);
- AddStringSummary(coregraphics_category_sp,
- "(x=${var.x}, y=${var.y})",
- ConstString("CGPoint"),
- objc_flags);
- AddStringSummary(coregraphics_category_sp,
- "origin=${var.origin} size=${var.size}",
- ConstString("CGRect"),
- objc_flags);
- TypeCategoryImpl::SharedPointer coreservices_category_sp = GetCategory(m_coreservices_category_name);
+ AddOneLineSummary (appkit_category_sp,
+ ConstString("NSPoint"),
+ objc_flags);
+ AddOneLineSummary (appkit_category_sp,
+ ConstString("NSSize"),
+ objc_flags);
+ AddOneLineSummary (appkit_category_sp,
+ ConstString("NSRect"),
+ objc_flags);
+
+ AddOneLineSummary (coregraphics_category_sp,
+ ConstString("CGSize"),
+ objc_flags);
+ AddOneLineSummary (coregraphics_category_sp,
+ ConstString("CGPoint"),
+ objc_flags);
+ AddOneLineSummary (coregraphics_category_sp,
+ ConstString("CGRect"),
+ objc_flags);
AddStringSummary(coreservices_category_sp,
"red=${var.red} green=${var.green} blue=${var.blue}",
@@ -1236,8 +1333,6 @@ FormatManager::LoadObjCFormatters()
ConstString("HIRect"),
objc_flags);
- TypeCategoryImpl::SharedPointer appkit_category_sp = GetCategory(m_appkit_category_name);
-
TypeSummaryImpl::Flags appkit_flags;
appkit_flags.SetCascades(true)
.SetSkipPointers(false)
@@ -1307,6 +1402,8 @@ FormatManager::LoadObjCFormatters()
AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "NSOrderedSet synthetic children", ConstString("NSOrderedSet"), ScriptedSyntheticChildren::Flags());
AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSOrderedSetI synthetic children", ConstString("__NSOrderedSetI"), ScriptedSyntheticChildren::Flags());
AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSOrderedSetM synthetic children", ConstString("__NSOrderedSetM"), ScriptedSyntheticChildren::Flags());
+
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSIndexPathSyntheticFrontEndCreator, "NSIndexPath synthetic children", ConstString("NSIndexPath"), ScriptedSyntheticChildren::Flags());
AddCXXSummary(corefoundation_category_sp,lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", ConstString("CFBagRef"), appkit_flags);
AddCXXSummary(corefoundation_category_sp,lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", ConstString("__CFBag"), appkit_flags);
@@ -1471,8 +1568,22 @@ FormatManager::LoadHardcodedFormatters()
}
{
// insert code to load summaries here
+ m_hardcoded_summaries.push_back(
+ [](lldb_private::ValueObject& valobj,
+ lldb::DynamicValueType,
+ FormatManager&) -> TypeSummaryImpl::SharedPointer {
+ static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(TypeSummaryImpl::Flags(), lldb_private::formatters::FunctionPointerSummaryProvider, "Function pointer summary provider"));
+ if (valobj.GetClangType().IsFunctionPointerType())
+ {
+ return formatter_sp;
+ }
+ return nullptr;
+ });
}
{
// insert code to load synthetics here
}
+ {
+ // insert code to load validators here
+ }
}
diff --git a/source/DataFormatters/LibCxx.cpp b/source/DataFormatters/LibCxx.cpp
index 174202661f03..26bbcf91242f 100644
--- a/source/DataFormatters/LibCxx.cpp
+++ b/source/DataFormatters/LibCxx.cpp
@@ -27,7 +27,7 @@ using namespace lldb_private;
using namespace lldb_private::formatters;
bool
-lldb_private::formatters::LibcxxSmartPointerSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::LibcxxSmartPointerSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
if (!valobj_sp)
@@ -143,7 +143,7 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (si
if (bit_set && buffer_sp && buffer_sp->GetBytes())
*(buffer_sp->GetBytes()) = 1; // regardless of endianness, anything non-zero is true
StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- ValueObjectSP retval_sp(ValueObject::CreateValueObjectFromData(name.GetData(), DataExtractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()), m_exe_ctx_ref, m_bool_type));
+ ValueObjectSP retval_sp(CreateValueObjectFromData(name.GetData(), DataExtractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()), m_exe_ctx_ref, m_bool_type));
if (retval_sp)
m_children[idx] = retval_sp;
return retval_sp;
@@ -378,7 +378,7 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex (siz
return lldb::ValueObjectSP();
uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0);
DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
- m_count_sp = ValueObject::CreateValueObjectFromData("count", data, valobj_sp->GetExecutionContextRef(), shared_owners_sp->GetClangType());
+ m_count_sp = CreateValueObjectFromData("count", data, valobj_sp->GetExecutionContextRef(), shared_owners_sp->GetClangType());
}
return m_count_sp;
}
@@ -391,7 +391,7 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex (siz
return lldb::ValueObjectSP();
uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0);
DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
- m_weak_count_sp = ValueObject::CreateValueObjectFromData("count", data, valobj_sp->GetExecutionContextRef(), shared_weak_owners_sp->GetClangType());
+ m_weak_count_sp = CreateValueObjectFromData("count", data, valobj_sp->GetExecutionContextRef(), shared_weak_owners_sp->GetClangType());
}
return m_weak_count_sp;
}
@@ -450,111 +450,8 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator (CXXSyntheticC
return (new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp));
}
-lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::LibcxxStdVectorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
- SyntheticChildrenFrontEnd(*valobj_sp.get()),
- m_start(NULL),
- m_finish(NULL),
- m_element_type(),
- m_element_size(0),
- m_children()
-{
- if (valobj_sp)
- Update();
-}
-
-size_t
-lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren ()
-{
- if (!m_start || !m_finish)
- return 0;
- uint64_t start_val = m_start->GetValueAsUnsigned(0);
- uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
-
- if (start_val == 0 || finish_val == 0)
- return 0;
-
- if (start_val >= finish_val)
- return 0;
-
- size_t num_children = (finish_val - start_val);
- if (num_children % m_element_size)
- return 0;
- return num_children/m_element_size;
-}
-
-lldb::ValueObjectSP
-lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
-{
- if (!m_start || !m_finish)
- return lldb::ValueObjectSP();
-
- auto cached = m_children.find(idx);
- if (cached != m_children.end())
- return cached->second;
-
- uint64_t offset = idx * m_element_size;
- offset = offset + m_start->GetValueAsUnsigned(0);
- StreamString name;
- name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- ValueObjectSP child_sp = ValueObject::CreateValueObjectFromAddress(name.GetData(), offset, m_backend.GetExecutionContextRef(), m_element_type);
- m_children[idx] = child_sp;
- return child_sp;
-}
-
-bool
-lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update()
-{
- m_start = m_finish = NULL;
- m_children.clear();
- ValueObjectSP data_type_finder_sp(m_backend.GetChildMemberWithName(ConstString("__end_cap_"),true));
- if (!data_type_finder_sp)
- return false;
- data_type_finder_sp = data_type_finder_sp->GetChildMemberWithName(ConstString("__first_"),true);
- if (!data_type_finder_sp)
- return false;
- m_element_type = data_type_finder_sp->GetClangType().GetPointeeType();
- m_element_size = m_element_type.GetByteSize();
-
- if (m_element_size > 0)
- {
- // store raw pointers or end up with a circular dependency
- m_start = m_backend.GetChildMemberWithName(ConstString("__begin_"),true).get();
- m_finish = m_backend.GetChildMemberWithName(ConstString("__end_"),true).get();
- }
- return false;
-}
-
-bool
-lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::MightHaveChildren ()
-{
- return true;
-}
-
-size_t
-lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
-{
- if (!m_start || !m_finish)
- return UINT32_MAX;
- return ExtractIndexFromString(name.GetCString());
-}
-
-lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::~LibcxxStdVectorSyntheticFrontEnd ()
-{
- // these need to stay around because they are child objects who will follow their parent's life cycle
- // delete m_start;
- // delete m_finish;
-}
-
-SyntheticChildrenFrontEnd*
-lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
-{
- if (!valobj_sp)
- return NULL;
- return (new LibcxxStdVectorSyntheticFrontEnd(valobj_sp));
-}
-
bool
-lldb_private::formatters::LibcxxContainerSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::LibcxxContainerSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
if (valobj.IsPointerType())
{
diff --git a/source/DataFormatters/LibCxxInitializerList.cpp b/source/DataFormatters/LibCxxInitializerList.cpp
new file mode 100644
index 000000000000..e76b0bec95ce
--- /dev/null
+++ b/source/DataFormatters/LibCxxInitializerList.cpp
@@ -0,0 +1,145 @@
+//===-- LibCxxInitializerList.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/DataFormatters/CXXFormatterFunctions.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/ValueObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+ namespace formatters {
+ class LibcxxInitializerListSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ LibcxxInitializerListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~LibcxxInitializerListSyntheticFrontEnd ();
+ private:
+ ValueObject* m_start;
+ ClangASTType m_element_type;
+ uint32_t m_element_size;
+ size_t m_num_elements;
+ std::map<size_t,lldb::ValueObjectSP> m_children;
+ };
+ }
+}
+
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::LibcxxInitializerListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_start(NULL),
+m_element_type(),
+m_element_size(0),
+m_num_elements(0),
+m_children()
+{
+ if (valobj_sp)
+ Update();
+}
+
+size_t
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::CalculateNumChildren ()
+{
+ static ConstString g___size_("__size_");
+ m_num_elements = 0;
+ ValueObjectSP size_sp(m_backend.GetChildMemberWithName(g___size_, true));
+ if (size_sp)
+ m_num_elements = size_sp->GetValueAsUnsigned(0);
+ return m_num_elements;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (!m_start)
+ return lldb::ValueObjectSP();
+
+ auto cached = m_children.find(idx);
+ if (cached != m_children.end())
+ return cached->second;
+
+ uint64_t offset = idx * m_element_size;
+ offset = offset + m_start->GetValueAsUnsigned(0);
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ ValueObjectSP child_sp = CreateValueObjectFromAddress(name.GetData(), offset, m_backend.GetExecutionContextRef(), m_element_type);
+ m_children[idx] = child_sp;
+ return child_sp;
+}
+
+bool
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::Update()
+{
+ static ConstString g___begin_("__begin_");
+
+ m_start = nullptr;
+ m_num_elements = 0;
+ m_children.clear();
+ lldb::TemplateArgumentKind kind;
+ m_element_type = m_backend.GetClangType().GetTemplateArgument(0, kind);
+ if (kind != lldb::eTemplateArgumentKindType || false == m_element_type.IsValid())
+ return false;
+
+ m_element_size = m_element_type.GetByteSize();
+
+ if (m_element_size > 0)
+ m_start = m_backend.GetChildMemberWithName(g___begin_,true).get(); // store raw pointers or end up with a circular dependency
+
+ return false;
+}
+
+bool
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (!m_start)
+ return UINT32_MAX;
+ return ExtractIndexFromString(name.GetCString());
+}
+
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::~LibcxxInitializerListSyntheticFrontEnd ()
+{
+ // this needs to stay around because it's a child object who will follow its parent's life cycle
+ // delete m_start;
+}
+
+lldb_private::SyntheticChildrenFrontEnd*
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ if (!valobj_sp)
+ return NULL;
+ return (new LibcxxInitializerListSyntheticFrontEnd(valobj_sp));
+}
+
diff --git a/source/DataFormatters/LibCxxList.cpp b/source/DataFormatters/LibCxxList.cpp
index 7d6db1a0ccd4..5bb6ce07480f 100644
--- a/source/DataFormatters/LibCxxList.cpp
+++ b/source/DataFormatters/LibCxxList.cpp
@@ -25,6 +25,47 @@ using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
+namespace lldb_private {
+ namespace formatters {
+ class LibcxxStdListSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~LibcxxStdListSyntheticFrontEnd ();
+ private:
+ bool
+ HasLoop(size_t);
+
+ size_t m_list_capping_size;
+ static const bool g_use_loop_detect = true;
+ size_t m_loop_detected;
+ lldb::addr_t m_node_address;
+ ValueObject* m_head;
+ ValueObject* m_tail;
+ ClangASTType m_element_type;
+ size_t m_count;
+ std::map<size_t,lldb::ValueObjectSP> m_children;
+ };
+ }
+}
+
class ListEntry
{
public:
@@ -150,6 +191,7 @@ private:
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp.get()),
m_list_capping_size(0),
+m_loop_detected(0),
m_node_address(),
m_head(NULL),
m_tail(NULL),
@@ -162,14 +204,15 @@ m_children()
}
bool
-lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop()
+lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop(size_t count)
{
if (g_use_loop_detect == false)
return false;
// don't bother checking for a loop if we won't actually need to jump nodes
if (m_count < 2)
return false;
- auto steps_left = m_count;
+ auto steps_left = std::min(count,m_count);
+ auto steps_left_save = steps_left;
ListEntry slow(m_head);
ListEntry fast(m_head);
while (steps_left-- > 0)
@@ -185,6 +228,7 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop()
if (slow == fast)
return true;
}
+ m_loop_detected = steps_left_save;
return false;
}
@@ -206,9 +250,7 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren (
}
if (m_count != UINT32_MAX)
{
- if (!HasLoop())
- return m_count;
- return m_count = 0;
+ return m_count;
}
else
{
@@ -220,8 +262,6 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren (
return 0;
if (next_val == prev_val)
return 1;
- if (HasLoop())
- return 0;
uint64_t size = 2;
ListEntry current(m_head);
while (current.next() && current.next().value() != m_node_address)
@@ -248,6 +288,10 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_
if (cached != m_children.end())
return cached->second;
+ if (m_loop_detected <= idx)
+ if (HasLoop(idx))
+ return lldb::ValueObjectSP();
+
ListIterator current(m_head);
ValueObjectSP current_sp(current.advance(idx));
if (!current_sp)
@@ -264,7 +308,7 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_
StreamString name;
name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
+ return (m_children[idx] = CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
}
bool
@@ -273,6 +317,7 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update()
m_head = m_tail = NULL;
m_node_address = 0;
m_count = UINT32_MAX;
+ m_loop_detected = false;
Error err;
ValueObjectSP backend_addr(m_backend.AddressOf(err));
m_list_capping_size = 0;
diff --git a/source/DataFormatters/LibCxxMap.cpp b/source/DataFormatters/LibCxxMap.cpp
index e665f29622d8..82e747e2db08 100644
--- a/source/DataFormatters/LibCxxMap.cpp
+++ b/source/DataFormatters/LibCxxMap.cpp
@@ -25,40 +25,84 @@ using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
+namespace lldb_private {
+ namespace formatters {
+ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ LibcxxStdMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~LibcxxStdMapSyntheticFrontEnd ();
+ private:
+ bool
+ GetDataType();
+
+ void
+ GetValueOffset (const lldb::ValueObjectSP& node);
+
+ ValueObject* m_tree;
+ ValueObject* m_root_node;
+ ClangASTType m_element_type;
+ uint32_t m_skip_size;
+ size_t m_count;
+ std::map<size_t,lldb::ValueObjectSP> m_children;
+ };
+ }
+}
+
class MapEntry
{
public:
MapEntry () {}
- MapEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
+ explicit MapEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
MapEntry (const MapEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {}
- MapEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
+ explicit MapEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
ValueObjectSP
- left ()
+ left () const
{
+ static ConstString g_left("__left_");
if (!m_entry_sp)
return m_entry_sp;
- return m_entry_sp->GetChildMemberWithName(ConstString("__left_"), true);
+ return m_entry_sp->GetChildMemberWithName(g_left, true);
}
ValueObjectSP
- right ()
+ right () const
{
+ static ConstString g_right("__right_");
if (!m_entry_sp)
return m_entry_sp;
- return m_entry_sp->GetChildMemberWithName(ConstString("__right_"), true);
+ return m_entry_sp->GetChildMemberWithName(g_right, true);
}
ValueObjectSP
- parent ()
+ parent () const
{
+ static ConstString g_parent("__parent_");
if (!m_entry_sp)
return m_entry_sp;
- return m_entry_sp->GetChildMemberWithName(ConstString("__parent_"), true);
+ return m_entry_sp->GetChildMemberWithName(g_parent, true);
}
uint64_t
- value ()
+ value () const
{
if (!m_entry_sp)
return 0;
@@ -66,7 +110,7 @@ public:
}
bool
- error ()
+ error () const
{
if (!m_entry_sp)
return true;
@@ -74,13 +118,13 @@ public:
}
bool
- null()
+ null() const
{
return (value() == 0);
}
ValueObjectSP
- GetEntry ()
+ GetEntry () const
{
return m_entry_sp;
}
@@ -119,27 +163,18 @@ public:
ValueObjectSP
advance (size_t count)
{
+ ValueObjectSP fail(nullptr);
if (m_error)
- return lldb::ValueObjectSP();
- if (count == 0)
- return m_entry.GetEntry();
- if (count == 1)
- {
- next ();
- return m_entry.GetEntry();
- }
+ return fail;
size_t steps = 0;
while (count > 0)
{
- if (m_error)
- return lldb::ValueObjectSP();
- next ();
- count--;
- if (m_entry.null())
- return lldb::ValueObjectSP();
- steps++;
- if (steps > m_max_depth)
- return lldb::ValueObjectSP();
+ next();
+ count--, steps++;
+ if (m_error ||
+ m_entry.null() ||
+ (steps > m_max_depth))
+ return fail;
}
return m_entry.GetEntry();
}
@@ -147,16 +182,39 @@ protected:
void
next ()
{
- m_entry.SetEntry(increment(m_entry.GetEntry()));
+ if (m_entry.null())
+ return;
+ MapEntry right(m_entry.right());
+ if (right.null() == false)
+ {
+ m_entry = tree_min(std::move(right));
+ return;
+ }
+ size_t steps = 0;
+ while (!is_left_child(m_entry))
+ {
+ if (m_entry.error())
+ {
+ m_error = true;
+ return;
+ }
+ m_entry.SetEntry(m_entry.parent());
+ steps++;
+ if (steps > m_max_depth)
+ {
+ m_entry = MapEntry();
+ return;
+ }
+ }
+ m_entry = MapEntry(m_entry.parent());
}
private:
- ValueObjectSP
- tree_min (ValueObjectSP x_sp)
+ MapEntry
+ tree_min (MapEntry&& x)
{
- MapEntry x(x_sp);
if (x.null())
- return ValueObjectSP();
+ return MapEntry();
MapEntry left(x.left());
size_t steps = 0;
while (left.null() == false)
@@ -164,42 +222,20 @@ private:
if (left.error())
{
m_error = true;
- return lldb::ValueObjectSP();
+ return MapEntry();
}
- x.SetEntry(left.GetEntry());
+ x = left;
left.SetEntry(x.left());
steps++;
if (steps > m_max_depth)
- return lldb::ValueObjectSP();
- }
- return x.GetEntry();
- }
-
- ValueObjectSP
- tree_max (ValueObjectSP x_sp)
- {
- MapEntry x(x_sp);
- if (x.null())
- return ValueObjectSP();
- MapEntry right(x.right());
- size_t steps = 0;
- while (right.null() == false)
- {
- if (right.error())
- return lldb::ValueObjectSP();
- x.SetEntry(right.GetEntry());
- right.SetEntry(x.right());
- steps++;
- if (steps > m_max_depth)
- return lldb::ValueObjectSP();
+ return MapEntry();
}
- return x.GetEntry();
+ return x;
}
-
+
bool
- is_left_child (ValueObjectSP x_sp)
+ is_left_child (const MapEntry& x)
{
- MapEntry x(x_sp);
if (x.null())
return false;
MapEntry rhs(x.parent());
@@ -207,31 +243,6 @@ private:
return x.value() == rhs.value();
}
- ValueObjectSP
- increment (ValueObjectSP x_sp)
- {
- MapEntry node(x_sp);
- if (node.null())
- return ValueObjectSP();
- MapEntry right(node.right());
- if (right.null() == false)
- return tree_min(right.GetEntry());
- size_t steps = 0;
- while (!is_left_child(node.GetEntry()))
- {
- if (node.error())
- {
- m_error = true;
- return lldb::ValueObjectSP();
- }
- node.SetEntry(node.parent());
- steps++;
- if (steps > m_max_depth)
- return lldb::ValueObjectSP();
- }
- return node.parent();
- }
-
MapEntry m_entry;
size_t m_max_depth;
bool m_error;
@@ -302,6 +313,10 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset (const l
lldb::ValueObjectSP
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
+ static ConstString g___cc("__cc");
+ static ConstString g___nc("__nc");
+
+
if (idx >= CalculateNumChildren())
return lldb::ValueObjectSP();
if (m_tree == NULL || m_root_node == NULL)
@@ -375,7 +390,31 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t
}
StreamString name;
name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
+ auto potential_child_sp = CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type);
+ if (potential_child_sp)
+ {
+ switch (potential_child_sp->GetNumChildren())
+ {
+ case 1:
+ {
+ auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
+ if (child0_sp && child0_sp->GetName() == g___cc)
+ potential_child_sp = child0_sp;
+ break;
+ }
+ case 2:
+ {
+ auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
+ auto child1_sp = potential_child_sp->GetChildAtIndex(1, true);
+ if (child0_sp && child0_sp->GetName() == g___cc &&
+ child1_sp && child1_sp->GetName() == g___nc)
+ potential_child_sp = child0_sp;
+ break;
+ }
+ }
+ potential_child_sp->SetName(ConstString(name.GetData()));
+ }
+ return (m_children[idx] = potential_child_sp);
}
bool
diff --git a/source/DataFormatters/LibCxxUnorderedMap.cpp b/source/DataFormatters/LibCxxUnorderedMap.cpp
index bf68f20955b5..da2a88966f5e 100644
--- a/source/DataFormatters/LibCxxUnorderedMap.cpp
+++ b/source/DataFormatters/LibCxxUnorderedMap.cpp
@@ -25,6 +25,41 @@ using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
+namespace lldb_private {
+ namespace formatters {
+ class LibcxxStdUnorderedMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ LibcxxStdUnorderedMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~LibcxxStdUnorderedMapSyntheticFrontEnd ();
+ private:
+
+ ValueObject* m_tree;
+ size_t m_num_elements;
+ ValueObject* m_next_element;
+ std::map<size_t,lldb::ValueObjectSP> m_children;
+ std::vector<std::pair<ValueObject*, uint64_t> > m_elements_cache;
+ };
+ }
+}
+
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::LibcxxStdUnorderedMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp.get()),
m_tree(NULL),
diff --git a/source/DataFormatters/LibCxxVector.cpp b/source/DataFormatters/LibCxxVector.cpp
new file mode 100644
index 000000000000..26c62afbed2b
--- /dev/null
+++ b/source/DataFormatters/LibCxxVector.cpp
@@ -0,0 +1,157 @@
+//===-- LibCxxVector.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/DataFormatters/CXXFormatterFunctions.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/ValueObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+ namespace formatters {
+ class LibcxxStdVectorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ LibcxxStdVectorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~LibcxxStdVectorSyntheticFrontEnd ();
+ private:
+ ValueObject* m_start;
+ ValueObject* m_finish;
+ ClangASTType m_element_type;
+ uint32_t m_element_size;
+ std::map<size_t,lldb::ValueObjectSP> m_children;
+ };
+ }
+}
+
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::LibcxxStdVectorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_start(NULL),
+m_finish(NULL),
+m_element_type(),
+m_element_size(0),
+m_children()
+{
+ if (valobj_sp)
+ Update();
+}
+
+size_t
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren ()
+{
+ if (!m_start || !m_finish)
+ return 0;
+ uint64_t start_val = m_start->GetValueAsUnsigned(0);
+ uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
+
+ if (start_val == 0 || finish_val == 0)
+ return 0;
+
+ if (start_val >= finish_val)
+ return 0;
+
+ size_t num_children = (finish_val - start_val);
+ if (num_children % m_element_size)
+ return 0;
+ return num_children/m_element_size;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (!m_start || !m_finish)
+ return lldb::ValueObjectSP();
+
+ auto cached = m_children.find(idx);
+ if (cached != m_children.end())
+ return cached->second;
+
+ uint64_t offset = idx * m_element_size;
+ offset = offset + m_start->GetValueAsUnsigned(0);
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ ValueObjectSP child_sp = CreateValueObjectFromAddress(name.GetData(), offset, m_backend.GetExecutionContextRef(), m_element_type);
+ m_children[idx] = child_sp;
+ return child_sp;
+}
+
+bool
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update()
+{
+ m_start = m_finish = NULL;
+ m_children.clear();
+ ValueObjectSP data_type_finder_sp(m_backend.GetChildMemberWithName(ConstString("__end_cap_"),true));
+ if (!data_type_finder_sp)
+ return false;
+ data_type_finder_sp = data_type_finder_sp->GetChildMemberWithName(ConstString("__first_"),true);
+ if (!data_type_finder_sp)
+ return false;
+ m_element_type = data_type_finder_sp->GetClangType().GetPointeeType();
+ m_element_size = m_element_type.GetByteSize();
+
+ if (m_element_size > 0)
+ {
+ // store raw pointers or end up with a circular dependency
+ m_start = m_backend.GetChildMemberWithName(ConstString("__begin_"),true).get();
+ m_finish = m_backend.GetChildMemberWithName(ConstString("__end_"),true).get();
+ }
+ return false;
+}
+
+bool
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (!m_start || !m_finish)
+ return UINT32_MAX;
+ return ExtractIndexFromString(name.GetCString());
+}
+
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::~LibcxxStdVectorSyntheticFrontEnd ()
+{
+ // these need to stay around because they are child objects who will follow their parent's life cycle
+ // delete m_start;
+ // delete m_finish;
+}
+
+lldb_private::SyntheticChildrenFrontEnd*
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ if (!valobj_sp)
+ return NULL;
+ return (new LibcxxStdVectorSyntheticFrontEnd(valobj_sp));
+}
+
diff --git a/source/DataFormatters/LibStdcpp.cpp b/source/DataFormatters/LibStdcpp.cpp
index f2d617323cca..b8f031ceeb2f 100644
--- a/source/DataFormatters/LibStdcpp.cpp
+++ b/source/DataFormatters/LibStdcpp.cpp
@@ -276,7 +276,7 @@ lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex
if (m_pair_address != 0 && m_pair_type)
{
if (!m_pair_sp)
- m_pair_sp = ValueObject::CreateValueObjectFromAddress("pair", m_pair_address, m_exe_ctx_ref, m_pair_type);
+ m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address, m_exe_ctx_ref, m_pair_type);
if (m_pair_sp)
return m_pair_sp->GetChildAtIndex(idx, true);
}
diff --git a/source/DataFormatters/NSArray.cpp b/source/DataFormatters/NSArray.cpp
index 16635381f94f..e242155f4fef 100644
--- a/source/DataFormatters/NSArray.cpp
+++ b/source/DataFormatters/NSArray.cpp
@@ -228,7 +228,7 @@ namespace lldb_private {
}
bool
-lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -341,10 +341,10 @@ lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx
object_at_idx += (pyhs_idx * m_ptr_size);
StreamString idx_name;
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(),
- object_at_idx,
- m_exe_ctx_ref,
- m_id_type);
+ lldb::ValueObjectSP retval_sp = CreateValueObjectFromAddress(idx_name.GetData(),
+ object_at_idx,
+ m_exe_ctx_ref,
+ m_id_type);
m_children.push_back(retval_sp);
return retval_sp;
}
@@ -604,7 +604,10 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx
return lldb::ValueObjectSP();
StreamString idx_name;
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(), object_at_idx, m_exe_ctx_ref, m_id_type);
+ lldb::ValueObjectSP retval_sp = CreateValueObjectFromAddress(idx_name.GetData(),
+ object_at_idx,
+ m_exe_ctx_ref,
+ m_id_type);
m_children.push_back(retval_sp);
return retval_sp;
}
@@ -624,7 +627,7 @@ SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCre
ClangASTType valobj_type(valobj_sp->GetClangType());
Flags flags(valobj_type.GetTypeInfo());
- if (flags.IsClear(ClangASTType::eTypeIsPointer))
+ if (flags.IsClear(eTypeIsPointer))
{
Error error;
valobj_sp = valobj_sp->AddressOf(error);
diff --git a/source/DataFormatters/NSDictionary.cpp b/source/DataFormatters/NSDictionary.cpp
index ddd1e2e7ca90..fdac05192c46 100644
--- a/source/DataFormatters/NSDictionary.cpp
+++ b/source/DataFormatters/NSDictionary.cpp
@@ -36,52 +36,167 @@ GetLLDBNSPairType (TargetSP target_sp)
if (target_ast_context)
{
- clang::ASTContext *ast = target_ast_context->getASTContext();
+ ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair");
- if (ast)
+ clang_type = target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(g___lldb_autogen_nspair);
+
+ if (!clang_type)
{
- const char* type_name = "__lldb_autogen_nspair";
+ clang_type = target_ast_context->CreateRecordType(NULL, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(), clang::TTK_Struct, lldb::eLanguageTypeC);
- clang::IdentifierInfo &myIdent = ast->Idents.get(type_name);
- clang::DeclarationName myName = ast->DeclarationNames.getIdentifier(&myIdent);
-
- clang::DeclContext::lookup_const_result result = ast->getTranslationUnitDecl()->lookup(myName);
-
- for (clang::NamedDecl *named_decl : result)
- {
- if (const clang::CXXRecordDecl *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(named_decl))
- {
- clang_type.SetClangType(ast, clang::QualType(record_decl->getTypeForDecl(), 0));
- break;
- }
- else
- {
- // somebody else (the user?) has defined a type with the magic name already - fail!!!
- return clang_type;
- }
- }
-
- if (!clang_type)
+ if (clang_type)
{
- clang_type = target_ast_context->CreateRecordType(NULL, lldb::eAccessPublic, type_name, clang::TTK_Struct, lldb::eLanguageTypeC);
-
- if (clang_type)
- {
- clang_type.StartTagDeclarationDefinition();
- ClangASTType id_clang_type = target_ast_context->GetBasicType (eBasicTypeObjCID);
- clang_type.AddFieldToRecordType("key", id_clang_type, lldb::eAccessPublic, 0);
- clang_type.AddFieldToRecordType("value", id_clang_type, lldb::eAccessPublic, 0);
- clang_type.CompleteTagDeclarationDefinition();
- }
+ clang_type.StartTagDeclarationDefinition();
+ ClangASTType id_clang_type = target_ast_context->GetBasicType (eBasicTypeObjCID);
+ clang_type.AddFieldToRecordType("key", id_clang_type, lldb::eAccessPublic, 0);
+ clang_type.AddFieldToRecordType("value", id_clang_type, lldb::eAccessPublic, 0);
+ clang_type.CompleteTagDeclarationDefinition();
}
}
}
return clang_type;
}
+namespace lldb_private {
+ namespace formatters {
+ class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ private:
+ struct DataDescriptor_32
+ {
+ uint32_t _used : 26;
+ uint32_t _szidx : 6;
+ };
+ struct DataDescriptor_64
+ {
+ uint64_t _used : 58;
+ uint32_t _szidx : 6;
+ };
+
+ struct DictionaryItemDescriptor
+ {
+ lldb::addr_t key_ptr;
+ lldb::addr_t val_ptr;
+ lldb::ValueObjectSP valobj_sp;
+ };
+
+ public:
+ NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSDictionaryISyntheticFrontEnd ();
+ private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ lldb::ByteOrder m_order;
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+ lldb::addr_t m_data_ptr;
+ ClangASTType m_pair_type;
+ std::vector<DictionaryItemDescriptor> m_children;
+ };
+
+ class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ private:
+ struct DataDescriptor_32
+ {
+ uint32_t _used : 26;
+ uint32_t _kvo : 1;
+ uint32_t _size;
+ uint32_t _mutations;
+ uint32_t _objs_addr;
+ uint32_t _keys_addr;
+ };
+ struct DataDescriptor_64
+ {
+ uint64_t _used : 58;
+ uint32_t _kvo : 1;
+ uint64_t _size;
+ uint64_t _mutations;
+ uint64_t _objs_addr;
+ uint64_t _keys_addr;
+ };
+ struct DictionaryItemDescriptor
+ {
+ lldb::addr_t key_ptr;
+ lldb::addr_t val_ptr;
+ lldb::ValueObjectSP valobj_sp;
+ };
+ public:
+ NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSDictionaryMSyntheticFrontEnd ();
+ private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ lldb::ByteOrder m_order;
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+ ClangASTType m_pair_type;
+ std::vector<DictionaryItemDescriptor> m_children;
+ };
+
+ class NSDictionaryCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSDictionaryCodeRunningSyntheticFrontEnd ();
+ };
+ }
+}
+
template<bool name_entries>
bool
-lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -407,7 +522,10 @@ lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_
StreamString idx_name;
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
DataExtractor data(buffer_sp, m_order, m_ptr_size);
- dict_item.valobj_sp = ValueObject::CreateValueObjectFromData(idx_name.GetData(), data, m_exe_ctx_ref, m_pair_type);
+ dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(),
+ data,
+ m_exe_ctx_ref,
+ m_pair_type);
}
return dict_item.valobj_sp;
}
@@ -571,13 +689,16 @@ lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_
StreamString idx_name;
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
DataExtractor data(buffer_sp, m_order, m_ptr_size);
- dict_item.valobj_sp = ValueObject::CreateValueObjectFromData(idx_name.GetData(), data, m_exe_ctx_ref, m_pair_type);
+ dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(),
+ data,
+ m_exe_ctx_ref,
+ m_pair_type);
}
return dict_item.valobj_sp;
}
template bool
-lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&) ;
+lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
template bool
-lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&) ;
+lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
diff --git a/source/DataFormatters/NSIndexPath.cpp b/source/DataFormatters/NSIndexPath.cpp
new file mode 100644
index 000000000000..ee9583ef4cc1
--- /dev/null
+++ b/source/DataFormatters/NSIndexPath.cpp
@@ -0,0 +1,309 @@
+//===-- NSIndexPath.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/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Symbol/ClangASTContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+{
+public:
+ NSIndexPathSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+ SyntheticChildrenFrontEnd (*valobj_sp.get()),
+ m_ptr_size(0),
+ m_ast_ctx(nullptr),
+ m_uint_star_type()
+ {
+ m_ptr_size = m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
+ }
+
+ virtual size_t
+ CalculateNumChildren ()
+ {
+ return m_impl.GetNumIndexes();
+ }
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx)
+ {
+ return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
+ }
+
+ virtual bool
+ Update()
+ {
+ m_impl.m_mode = Mode::Invalid;
+
+ m_ast_ctx = ClangASTContext::GetASTContext(m_backend.GetClangType().GetASTContext());
+ if (!m_ast_ctx)
+ return false;
+
+ m_uint_star_type = m_ast_ctx->GetPointerSizedIntType(false);
+
+ static ConstString g__indexes("_indexes");
+ static ConstString g__length("_length");
+
+ ProcessSP process_sp = m_backend.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(m_backend));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint64_t info_bits(0),value_bits(0),payload(0);
+
+ if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload))
+ {
+ m_impl.m_mode = Mode::Inlined;
+ m_impl.m_inlined.SetIndexes(payload, *process_sp);
+ }
+ else
+ {
+ ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
+ ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
+
+ bool has_indexes(false),has_length(false);
+
+ for (size_t x = 0;
+ x < descriptor->GetNumIVars();
+ x++)
+ {
+ const auto& ivar = descriptor->GetIVarAtIndex(x);
+ if (ivar.m_name == g__indexes)
+ {
+ _indexes_id = ivar;
+ has_indexes = true;
+ }
+ else if (ivar.m_name == g__length)
+ {
+ _length_id = ivar;
+ has_length = true;
+ }
+
+ if (has_length && has_indexes)
+ break;
+ }
+
+ if (has_length && has_indexes)
+ {
+ m_impl.m_outsourced.m_indexes = m_backend.GetSyntheticChildAtOffset(_indexes_id.m_offset,
+ m_uint_star_type.GetPointerType(),
+ true).get();
+ ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(_length_id.m_offset,
+ m_uint_star_type,
+ true));
+ if (length_sp)
+ {
+ m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
+ if (m_impl.m_outsourced.m_indexes)
+ m_impl.m_mode = Mode::Outsourced;
+ }
+ }
+ }
+ return false;
+ }
+
+ virtual bool
+ MightHaveChildren ()
+ {
+ if (m_impl.m_mode == Mode::Invalid)
+ return false;
+ 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 lldb::ValueObjectSP
+ GetSyntheticValue () { return nullptr; }
+
+ virtual
+ ~NSIndexPathSyntheticFrontEnd () {}
+
+protected:
+ ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
+
+ enum class Mode {
+ Inlined,
+ Outsourced,
+ Invalid
+ };
+
+ struct Impl {
+ Mode m_mode;
+
+ size_t
+ GetNumIndexes ()
+ {
+ switch (m_mode)
+ {
+ case Mode::Inlined:
+ return m_inlined.GetNumIndexes();
+ case Mode::Outsourced:
+ return m_outsourced.m_count;
+ default:
+ return 0;
+ }
+ }
+
+ lldb::ValueObjectSP
+ GetIndexAtIndex (size_t idx, const ClangASTType& desired_type)
+ {
+ if (idx >= GetNumIndexes())
+ return nullptr;
+ switch (m_mode)
+ {
+ default: return nullptr;
+ case Mode::Inlined:
+ return m_inlined.GetIndexAtIndex (idx, desired_type);
+ case Mode::Outsourced:
+ return m_outsourced.GetIndexAtIndex (idx);
+ }
+ }
+
+ 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};
+ }
+
+ };
+ 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;
+ }
+ };
+
+ union {
+ struct InlinedIndexes m_inlined;
+ struct OutsourcedIndexes m_outsourced;
+ };
+ } m_impl;
+
+ uint32_t m_ptr_size;
+ ClangASTContext* m_ast_ctx;
+ ClangASTType m_uint_star_type;
+};
+
+namespace lldb_private {
+ namespace formatters {
+
+ SyntheticChildrenFrontEnd* NSIndexPathSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+ {
+ if (valobj_sp)
+ return new NSIndexPathSyntheticFrontEnd(valobj_sp);
+ return nullptr;
+ }
+ }
+}
diff --git a/source/DataFormatters/NSSet.cpp b/source/DataFormatters/NSSet.cpp
index 3c7c003ed95a..194d1bd29ea1 100644
--- a/source/DataFormatters/NSSet.cpp
+++ b/source/DataFormatters/NSSet.cpp
@@ -25,9 +25,165 @@ using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
+namespace lldb_private {
+ namespace formatters {
+ class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ private:
+ struct DataDescriptor_32
+ {
+ uint32_t _used : 26;
+ uint32_t _szidx : 6;
+ };
+ struct DataDescriptor_64
+ {
+ uint64_t _used : 58;
+ uint32_t _szidx : 6;
+ };
+
+ struct SetItemDescriptor
+ {
+ lldb::addr_t item_ptr;
+ lldb::ValueObjectSP valobj_sp;
+ };
+
+ public:
+ NSSetISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSSetISyntheticFrontEnd ();
+ private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+ lldb::addr_t m_data_ptr;
+ std::vector<SetItemDescriptor> m_children;
+ };
+
+ class NSOrderedSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ private:
+
+ public:
+ NSOrderedSetSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSOrderedSetSyntheticFrontEnd ();
+ private:
+ uint32_t m_count;
+ std::map<uint32_t,lldb::ValueObjectSP> m_children;
+ };
+
+ class NSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ private:
+ struct DataDescriptor_32
+ {
+ uint32_t _used : 26;
+ uint32_t _size;
+ uint32_t _mutations;
+ uint32_t _objs_addr;
+ };
+ struct DataDescriptor_64
+ {
+ uint64_t _used : 58;
+ uint64_t _size;
+ uint64_t _mutations;
+ uint64_t _objs_addr;
+ };
+ struct SetItemDescriptor
+ {
+ lldb::addr_t item_ptr;
+ lldb::ValueObjectSP valobj_sp;
+ };
+ public:
+ NSSetMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSSetMSyntheticFrontEnd ();
+ private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+ std::vector<SetItemDescriptor> m_children;
+ };
+
+ class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ NSSetCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSSetCodeRunningSyntheticFrontEnd ();
+ };
+ }
+}
+
template<bool cf_style>
bool
-lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& stream)
+lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
@@ -313,10 +469,10 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx)
process_sp->GetAddressByteSize());
set_item.valobj_sp =
- ValueObject::CreateValueObjectFromData(idx_name.GetData(),
- data,
- m_exe_ctx_ref,
- m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
+ CreateValueObjectFromData(idx_name.GetData(),
+ data,
+ m_exe_ctx_ref,
+ m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
}
return set_item.valobj_sp;
}
@@ -481,10 +637,10 @@ lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
process_sp->GetAddressByteSize());
set_item.valobj_sp =
- ValueObject::CreateValueObjectFromData(idx_name.GetData(),
- data,
- m_exe_ctx_ref,
- m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
+ CreateValueObjectFromData(idx_name.GetData(),
+ data,
+ m_exe_ctx_ref,
+ m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
}
return set_item.valobj_sp;
}
@@ -557,7 +713,7 @@ lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::~NSOrderedSetSyntheticF
}
template bool
-lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Stream& stream);
+lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options);
template bool
-lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream);
+lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options);
diff --git a/source/DataFormatters/StringPrinter.cpp b/source/DataFormatters/StringPrinter.cpp
new file mode 100644
index 000000000000..3af5931ad716
--- /dev/null
+++ b/source/DataFormatters/StringPrinter.cpp
@@ -0,0 +1,650 @@
+//===-- StringPrinter.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/StringPrinter.h"
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "llvm/Support/ConvertUTF.h"
+
+#include <ctype.h>
+#include <functional>
+#include <locale>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+// I can't use a std::unique_ptr for this because the Deleter is a template argument there
+// and I want the same type to represent both pointers I want to free and pointers I don't need
+// to free - which is what this class essentially is
+// It's very specialized to the needs of this file, and not suggested for general use
+template <typename T = uint8_t, typename U = char, typename S = size_t>
+struct StringPrinterBufferPointer
+{
+public:
+
+ typedef std::function<void(const T*)> Deleter;
+
+ StringPrinterBufferPointer (std::nullptr_t ptr) :
+ m_data(nullptr),
+ m_size(0),
+ m_deleter()
+ {}
+
+ StringPrinterBufferPointer(const T* bytes, S size, Deleter deleter = nullptr) :
+ m_data(bytes),
+ m_size(size),
+ m_deleter(deleter)
+ {}
+
+ StringPrinterBufferPointer(const U* bytes, S size, Deleter deleter = nullptr) :
+ m_data((T*)bytes),
+ m_size(size),
+ m_deleter(deleter)
+ {}
+
+ StringPrinterBufferPointer(StringPrinterBufferPointer&& rhs) :
+ m_data(rhs.m_data),
+ m_size(rhs.m_size),
+ m_deleter(rhs.m_deleter)
+ {
+ rhs.m_data = nullptr;
+ }
+
+ StringPrinterBufferPointer(const StringPrinterBufferPointer& rhs) :
+ m_data(rhs.m_data),
+ m_size(rhs.m_size),
+ m_deleter(rhs.m_deleter)
+ {
+ rhs.m_data = nullptr; // this is why m_data has to be mutable
+ }
+
+ const T*
+ GetBytes () const
+ {
+ return m_data;
+ }
+
+ const S
+ GetSize () const
+ {
+ return m_size;
+ }
+
+ ~StringPrinterBufferPointer ()
+ {
+ if (m_data && m_deleter)
+ m_deleter(m_data);
+ m_data = nullptr;
+ }
+
+ StringPrinterBufferPointer&
+ operator = (const StringPrinterBufferPointer& rhs)
+ {
+ if (m_data && m_deleter)
+ m_deleter(m_data);
+ m_data = rhs.m_data;
+ m_size = rhs.m_size;
+ m_deleter = rhs.m_deleter;
+ rhs.m_data = nullptr;
+ return *this;
+ }
+
+private:
+ mutable const T* m_data;
+ size_t m_size;
+ Deleter m_deleter;
+};
+
+// we define this for all values of type but only implement it for those we care about
+// that's good because we get linker errors for any unsupported type
+template <StringElementType type>
+static StringPrinterBufferPointer<>
+GetPrintableImpl(uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next);
+
+// mimic isprint() for Unicode codepoints
+static bool
+isprint(char32_t codepoint)
+{
+ if (codepoint <= 0x1F || codepoint == 0x7F) // C0
+ {
+ return false;
+ }
+ if (codepoint >= 0x80 && codepoint <= 0x9F) // C1
+ {
+ return false;
+ }
+ if (codepoint == 0x2028 || codepoint == 0x2029) // line/paragraph separators
+ {
+ return false;
+ }
+ if (codepoint == 0x200E || codepoint == 0x200F || (codepoint >= 0x202A && codepoint <= 0x202E)) // bidirectional text control
+ {
+ return false;
+ }
+ if (codepoint >= 0xFFF9 && codepoint <= 0xFFFF) // interlinears and generally specials
+ {
+ return false;
+ }
+ return true;
+}
+
+template <>
+StringPrinterBufferPointer<>
+GetPrintableImpl<StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
+{
+ StringPrinterBufferPointer<> retval = {nullptr};
+
+ switch (*buffer)
+ {
+ case 0:
+ retval = {"\\0",2};
+ break;
+ case '\a':
+ retval = {"\\a",2};
+ break;
+ case '\b':
+ retval = {"\\b",2};
+ break;
+ case '\f':
+ retval = {"\\f",2};
+ break;
+ case '\n':
+ retval = {"\\n",2};
+ break;
+ case '\r':
+ retval = {"\\r",2};
+ break;
+ case '\t':
+ retval = {"\\t",2};
+ break;
+ case '\v':
+ retval = {"\\v",2};
+ break;
+ case '\"':
+ retval = {"\\\"",2};
+ break;
+ case '\\':
+ retval = {"\\\\",2};
+ break;
+ default:
+ if (isprint(*buffer))
+ retval = {buffer,1};
+ else
+ {
+ retval = { new uint8_t[5],4,[] (const uint8_t* c) {delete[] c;} };
+ sprintf((char*)retval.GetBytes(),"\\x%02x",*buffer);
+ break;
+ }
+ }
+
+ next = buffer + 1;
+ return retval;
+}
+
+static char32_t
+ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1)
+{
+ return (c0-192)*64+(c1-128);
+}
+static char32_t
+ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2)
+{
+ return (c0-224)*4096+(c1-128)*64+(c2-128);
+}
+static char32_t
+ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3)
+{
+ return (c0-240)*262144+(c2-128)*4096+(c2-128)*64+(c3-128);
+}
+
+template <>
+StringPrinterBufferPointer<>
+GetPrintableImpl<StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
+{
+ StringPrinterBufferPointer<> retval {nullptr};
+
+ unsigned utf8_encoded_len = getNumBytesForUTF8(*buffer);
+
+ if (1+buffer_end-buffer < utf8_encoded_len)
+ {
+ // I don't have enough bytes - print whatever I have left
+ retval = {buffer,static_cast<size_t>(1+buffer_end-buffer)};
+ next = buffer_end+1;
+ return retval;
+ }
+
+ char32_t codepoint = 0;
+ switch (utf8_encoded_len)
+ {
+ case 1:
+ // this is just an ASCII byte - ask ASCII
+ return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next);
+ case 2:
+ codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1));
+ break;
+ case 3:
+ codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2));
+ break;
+ case 4:
+ codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2), (unsigned char)*(buffer+3));
+ break;
+ default:
+ // this is probably some bogus non-character thing
+ // just print it as-is and hope to sync up again soon
+ retval = {buffer,1};
+ next = buffer+1;
+ return retval;
+ }
+
+ if (codepoint)
+ {
+ switch (codepoint)
+ {
+ case 0:
+ retval = {"\\0",2};
+ break;
+ case '\a':
+ retval = {"\\a",2};
+ break;
+ case '\b':
+ retval = {"\\b",2};
+ break;
+ case '\f':
+ retval = {"\\f",2};
+ break;
+ case '\n':
+ retval = {"\\n",2};
+ break;
+ case '\r':
+ retval = {"\\r",2};
+ break;
+ case '\t':
+ retval = {"\\t",2};
+ break;
+ case '\v':
+ retval = {"\\v",2};
+ break;
+ case '\"':
+ retval = {"\\\"",2};
+ break;
+ case '\\':
+ retval = {"\\\\",2};
+ break;
+ default:
+ if (isprint(codepoint))
+ 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);
+ break;
+ }
+ }
+
+ next = buffer + utf8_encoded_len;
+ return retval;
+ }
+
+ // this should not happen - but just in case.. try to resync at some point
+ retval = {buffer,1};
+ next = buffer+1;
+ return retval;
+}
+
+// Given a sequence of bytes, this function returns:
+// a sequence of bytes to actually print out + a length
+// the following unscanned position of the buffer is in next
+static StringPrinterBufferPointer<>
+GetPrintable(StringElementType type, uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
+{
+ if (!buffer)
+ return {nullptr};
+
+ switch (type)
+ {
+ case StringElementType::ASCII:
+ return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next);
+ case StringElementType::UTF8:
+ return GetPrintableImpl<StringElementType::UTF8>(buffer, buffer_end, next);
+ default:
+ return {nullptr};
+ }
+}
+
+// use this call if you already have an LLDB-side buffer for the data
+template<typename SourceDataType>
+static bool
+DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
+ const SourceDataType*,
+ UTF8**,
+ UTF8*,
+ ConversionFlags),
+ const DataExtractor& data,
+ Stream& stream,
+ char prefix_token,
+ char quote,
+ uint32_t sourceSize,
+ bool escapeNonPrintables)
+{
+ if (prefix_token != 0)
+ stream.Printf("%c",prefix_token);
+ if (quote != 0)
+ stream.Printf("%c",quote);
+ if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd())
+ {
+ const int bufferSPSize = data.GetByteSize();
+ if (sourceSize == 0)
+ {
+ const int origin_encoding = 8*sizeof(SourceDataType);
+ sourceSize = bufferSPSize/(origin_encoding / 4);
+ }
+
+ SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart();
+ SourceDataType *data_end_ptr = data_ptr + sourceSize;
+
+ while (data_ptr < data_end_ptr)
+ {
+ if (!*data_ptr)
+ {
+ data_end_ptr = data_ptr;
+ break;
+ }
+ data_ptr++;
+ }
+
+ data_ptr = (SourceDataType*)data.GetDataStart();
+
+ lldb::DataBufferSP utf8_data_buffer_sp;
+ UTF8* utf8_data_ptr = nullptr;
+ UTF8* utf8_data_end_ptr = nullptr;
+
+ if (ConvertFunction)
+ {
+ 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 );
+ utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr
+ }
+ else
+ {
+ // just copy the pointers - the cast is necessary to make the compiler happy
+ // but this should only happen if we are reading UTF8 data
+ utf8_data_ptr = (UTF8*)data_ptr;
+ utf8_data_end_ptr = (UTF8*)data_end_ptr;
+ }
+
+ // since we tend to accept partial data (and even partially malformed data)
+ // we might end up with no NULL terminator before the end_ptr
+ // hence we need to take a slower route and ensure we stay within boundaries
+ for (;utf8_data_ptr < utf8_data_end_ptr;)
+ {
+ if (!*utf8_data_ptr)
+ break;
+
+ if (escapeNonPrintables)
+ {
+ uint8_t* next_data = nullptr;
+ auto printable = GetPrintable(StringElementType::UTF8, utf8_data_ptr, utf8_data_end_ptr, next_data);
+ auto printable_bytes = printable.GetBytes();
+ auto printable_size = printable.GetSize();
+ if (!printable_bytes || !next_data)
+ {
+ // GetPrintable() failed on us - print one byte in a desperate resync attempt
+ printable_bytes = utf8_data_ptr;
+ printable_size = 1;
+ next_data = utf8_data_ptr+1;
+ }
+ for (unsigned c = 0; c < printable_size; c++)
+ stream.Printf("%c", *(printable_bytes+c));
+ utf8_data_ptr = (uint8_t*)next_data;
+ }
+ else
+ {
+ stream.Printf("%c",*utf8_data_ptr);
+ utf8_data_ptr++;
+ }
+ }
+ }
+ if (quote != 0)
+ stream.Printf("%c",quote);
+ return true;
+}
+
+lldb_private::formatters::ReadStringAndDumpToStreamOptions::ReadStringAndDumpToStreamOptions (ValueObject& valobj) :
+ ReadStringAndDumpToStreamOptions()
+{
+ SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
+}
+
+lldb_private::formatters::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (ValueObject& valobj) :
+ ReadBufferAndDumpToStreamOptions()
+{
+ SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
+}
+
+
+namespace lldb_private
+{
+
+namespace formatters
+{
+
+template <>
+bool
+ReadStringAndDumpToStream<StringElementType::ASCII> (ReadStringAndDumpToStreamOptions options)
+{
+ assert(options.GetStream() && "need a Stream to print the string to");
+ Error my_error;
+ size_t my_data_read;
+
+ ProcessSP process_sp(options.GetProcessSP());
+
+ if (process_sp.get() == nullptr || options.GetLocation() == 0)
+ return false;
+
+ size_t size;
+
+ if (options.GetSourceSize() == 0)
+ size = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
+ else if (!options.GetIgnoreMaxLength())
+ size = std::min(options.GetSourceSize(),process_sp->GetTarget().GetMaximumSizeOfStringSummary());
+ else
+ size = options.GetSourceSize();
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0));
+
+ my_data_read = process_sp->ReadCStringFromMemory(options.GetLocation(), (char*)buffer_sp->GetBytes(), size, my_error);
+
+ if (my_error.Fail())
+ return false;
+
+ char prefix_token = options.GetPrefixToken();
+ char quote = options.GetQuote();
+
+ if (prefix_token != 0)
+ options.GetStream()->Printf("%c%c",prefix_token,quote);
+ else if (quote != 0)
+ options.GetStream()->Printf("%c",quote);
+
+ uint8_t* data_end = buffer_sp->GetBytes()+buffer_sp->GetByteSize();
+
+ // since we tend to accept partial data (and even partially malformed data)
+ // we might end up with no NULL terminator before the end_ptr
+ // hence we need to take a slower route and ensure we stay within boundaries
+ for (uint8_t* data = buffer_sp->GetBytes(); *data && (data < data_end);)
+ {
+ if (options.GetEscapeNonPrintables())
+ {
+ uint8_t* next_data = nullptr;
+ auto printable = GetPrintable(StringElementType::ASCII, data, data_end, next_data);
+ auto printable_bytes = printable.GetBytes();
+ auto printable_size = printable.GetSize();
+ if (!printable_bytes || !next_data)
+ {
+ // GetPrintable() failed on us - print one byte in a desperate resync attempt
+ printable_bytes = data;
+ printable_size = 1;
+ next_data = data+1;
+ }
+ for (unsigned c = 0; c < printable_size; c++)
+ options.GetStream()->Printf("%c", *(printable_bytes+c));
+ data = (uint8_t*)next_data;
+ }
+ else
+ {
+ options.GetStream()->Printf("%c",*data);
+ data++;
+ }
+ }
+
+ if (quote != 0)
+ options.GetStream()->Printf("%c",quote);
+
+ return true;
+}
+
+template<typename SourceDataType>
+static bool
+ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options,
+ ConversionResult (*ConvertFunction) (const SourceDataType**,
+ const SourceDataType*,
+ UTF8**,
+ UTF8*,
+ ConversionFlags))
+{
+ assert(options.GetStream() && "need a Stream to print the string to");
+
+ if (options.GetLocation() == 0 || options.GetLocation() == LLDB_INVALID_ADDRESS)
+ return false;
+
+ lldb::ProcessSP process_sp(options.GetProcessSP());
+
+ if (!process_sp)
+ return false;
+
+ const int type_width = sizeof(SourceDataType);
+ const int origin_encoding = 8 * type_width ;
+ if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
+ return false;
+ // if not UTF8, I need a conversion function to return proper UTF8
+ if (origin_encoding != 8 && !ConvertFunction)
+ return false;
+
+ if (!options.GetStream())
+ return false;
+
+ uint32_t sourceSize = options.GetSourceSize();
+ bool needs_zero_terminator = options.GetNeedsZeroTermination();
+
+ if (!sourceSize)
+ {
+ sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
+ needs_zero_terminator = true;
+ }
+ else
+ sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary());
+
+ const int bufferSPSize = sourceSize * type_width;
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
+
+ if (!buffer_sp->GetBytes())
+ return false;
+
+ 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);
+ else
+ data_read = process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error);
+
+ if (error.Fail())
+ {
+ options.GetStream()->Printf("unable to read data");
+ return true;
+ }
+
+ DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
+
+ return DumpUTFBufferToStream(ConvertFunction, data, *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), sourceSize, options.GetEscapeNonPrintables());
+}
+
+template <>
+bool
+ReadStringAndDumpToStream<StringElementType::UTF8> (ReadStringAndDumpToStreamOptions options)
+{
+ return ReadUTFBufferAndDumpToStream<UTF8>(options,
+ nullptr);
+}
+
+template <>
+bool
+ReadStringAndDumpToStream<StringElementType::UTF16> (ReadStringAndDumpToStreamOptions options)
+{
+ return ReadUTFBufferAndDumpToStream<UTF16>(options,
+ ConvertUTF16toUTF8);
+}
+
+template <>
+bool
+ReadStringAndDumpToStream<StringElementType::UTF32> (ReadStringAndDumpToStreamOptions options)
+{
+ return ReadUTFBufferAndDumpToStream<UTF32>(options,
+ ConvertUTF32toUTF8);
+}
+
+template <>
+bool
+ReadBufferAndDumpToStream<StringElementType::UTF8> (ReadBufferAndDumpToStreamOptions options)
+{
+ assert(options.GetStream() && "need a Stream to print the string to");
+
+ return DumpUTFBufferToStream<UTF8>(nullptr, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables());
+}
+
+template <>
+bool
+ReadBufferAndDumpToStream<StringElementType::ASCII> (ReadBufferAndDumpToStreamOptions options)
+{
+ // treat ASCII the same as UTF8
+ // FIXME: can we optimize ASCII some more?
+ return ReadBufferAndDumpToStream<StringElementType::UTF8>(options);
+}
+
+template <>
+bool
+ReadBufferAndDumpToStream<StringElementType::UTF16> (ReadBufferAndDumpToStreamOptions options)
+{
+ assert(options.GetStream() && "need a Stream to print the string to");
+
+ return DumpUTFBufferToStream(ConvertUTF16toUTF8, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables());
+}
+
+template <>
+bool
+ReadBufferAndDumpToStream<StringElementType::UTF32> (ReadBufferAndDumpToStreamOptions options)
+{
+ assert(options.GetStream() && "need a Stream to print the string to");
+
+ return DumpUTFBufferToStream(ConvertUTF32toUTF8, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables());
+}
+
+} // namespace formatters
+
+} // namespace lldb_private
diff --git a/source/DataFormatters/TypeCategory.cpp b/source/DataFormatters/TypeCategory.cpp
index 322d1cf55437..3df6884fe679 100644
--- a/source/DataFormatters/TypeCategory.cpp
+++ b/source/DataFormatters/TypeCategory.cpp
@@ -27,6 +27,7 @@ m_filter_cont("filter","regex-filter",clist),
#ifndef LLDB_DISABLE_PYTHON
m_synth_cont("synth","regex-synth",clist),
#endif
+m_validator_cont("validator","regex-validator",clist),
m_enabled(false),
m_change_listener(clist),
m_mutex(Mutex::eMutexTypeRecursive),
@@ -129,6 +130,22 @@ TypeCategoryImpl::Get (ValueObject& valobj,
return false;
}
+bool
+TypeCategoryImpl::Get (ValueObject& valobj,
+ const FormattersMatchVector& candidates,
+ lldb::TypeValidatorImplSP& entry,
+ uint32_t* reason)
+{
+ if (!IsEnabled())
+ return false;
+ if (GetTypeValidatorsContainer()->Get(candidates, entry, reason))
+ return true;
+ bool regex = GetRegexTypeValidatorsContainer()->Get(candidates, entry, reason);
+ if (regex && reason)
+ *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary;
+ return regex;
+}
+
void
TypeCategoryImpl::Clear (FormatCategoryItems items)
{
@@ -153,6 +170,11 @@ TypeCategoryImpl::Clear (FormatCategoryItems items)
if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth )
GetRegexTypeSyntheticsContainer()->Clear();
#endif
+
+ if ( (items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator )
+ GetTypeValidatorsContainer()->Clear();
+ if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator )
+ GetRegexTypeValidatorsContainer()->Clear();
}
bool
@@ -182,6 +204,12 @@ TypeCategoryImpl::Delete (ConstString name,
if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth )
success = GetRegexTypeSyntheticsContainer()->Delete(name) || success;
#endif
+
+ if ( (items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator )
+ success = GetTypeValidatorsContainer()->Delete(name) || success;
+ if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator )
+ success = GetRegexTypeValidatorsContainer()->Delete(name) || success;
+
return success;
}
@@ -211,6 +239,12 @@ TypeCategoryImpl::GetCount (FormatCategoryItems items)
if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth )
count += GetRegexTypeSyntheticsContainer()->GetCount();
#endif
+
+ if ( (items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator )
+ count += GetTypeValidatorsContainer()->GetCount();
+ if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator )
+ count += GetRegexTypeValidatorsContainer()->GetCount();
+
return count;
}
@@ -230,6 +264,7 @@ TypeCategoryImpl::AnyMatches(ConstString type_name,
#ifndef LLDB_DISABLE_PYTHON
ScriptedSyntheticChildren::SharedPointer synth_sp;
#endif
+ TypeValidatorImpl::SharedPointer validator_sp;
if ( (items & eFormatCategoryItemValue) == eFormatCategoryItemValue )
{
@@ -324,6 +359,30 @@ TypeCategoryImpl::AnyMatches(ConstString type_name,
}
}
#endif
+
+ if ( (items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator )
+ {
+ if (GetTypeValidatorsContainer()->Get(type_name, validator_sp))
+ {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemValidator;
+ return true;
+ }
+ }
+ if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator )
+ {
+ if (GetRegexTypeValidatorsContainer()->Get(type_name, validator_sp))
+ {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemRegexValidator;
+ return true;
+ }
+ }
+
return false;
}
@@ -393,6 +452,22 @@ TypeCategoryImpl::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp)
}
#endif
+TypeCategoryImpl::ValidatorContainer::MapValueType
+TypeCategoryImpl::GetValidatorForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ ValidatorContainer::MapValueType retval;
+
+ if (type_sp)
+ {
+ if (type_sp->IsRegex())
+ GetRegexTypeValidatorsContainer()->GetExact(ConstString(type_sp->GetName()),retval);
+ else
+ GetTypeValidatorsContainer()->GetExact(ConstString(type_sp->GetName()),retval);
+ }
+
+ return retval;
+}
+
lldb::TypeNameSpecifierImplSP
TypeCategoryImpl::GetTypeNameSpecifierForSummaryAtIndex (size_t index)
{
@@ -467,12 +542,30 @@ TypeCategoryImpl::GetTypeNameSpecifierForSyntheticAtIndex (size_t index)
}
#endif
+TypeCategoryImpl::ValidatorContainer::MapValueType
+TypeCategoryImpl::GetValidatorAtIndex (size_t index)
+{
+ if (index < GetTypeValidatorsContainer()->GetCount())
+ return GetTypeValidatorsContainer()->GetAtIndex(index);
+ else
+ return GetRegexTypeValidatorsContainer()->GetAtIndex(index-GetTypeValidatorsContainer()->GetCount());
+}
+
+lldb::TypeNameSpecifierImplSP
+TypeCategoryImpl::GetTypeNameSpecifierForValidatorAtIndex (size_t index)
+{
+ if (index < GetTypeValidatorsContainer()->GetCount())
+ return GetTypeValidatorsContainer()->GetTypeNameSpecifierAtIndex(index);
+ else
+ return GetRegexTypeValidatorsContainer()->GetTypeNameSpecifierAtIndex(index - GetTypeValidatorsContainer()->GetCount());
+}
+
void
TypeCategoryImpl::Enable (bool value, uint32_t position)
{
Mutex::Locker locker(m_mutex);
- m_enabled = value;
- m_enabled_position = position;
+ if ( (m_enabled = value) )
+ m_enabled_position = position;
if (m_change_listener)
m_change_listener->Changed();
}
diff --git a/source/DataFormatters/TypeCategoryMap.cpp b/source/DataFormatters/TypeCategoryMap.cpp
index c6dba1b9f4bd..ae34d0339011 100644
--- a/source/DataFormatters/TypeCategoryMap.cpp
+++ b/source/DataFormatters/TypeCategoryMap.cpp
@@ -120,6 +120,46 @@ TypeCategoryMap::Disable (ValueSP category)
}
void
+TypeCategoryMap::EnableAllCategories ()
+{
+ Mutex::Locker locker(m_map_mutex);
+ std::vector<ValueSP> sorted_categories(m_map.size(), ValueSP());
+ MapType::iterator iter = m_map.begin(), end = m_map.end();
+ for (; iter != end; ++iter)
+ {
+ if (iter->second->IsEnabled())
+ continue;
+ auto pos = iter->second->GetLastEnabledPosition();
+ if (pos >= sorted_categories.size())
+ {
+ auto iter = std::find_if(sorted_categories.begin(),
+ sorted_categories.end(),
+ [] (const ValueSP& sp) -> bool {
+ return sp.get() == nullptr;
+ });
+ pos = std::distance(sorted_categories.begin(), iter);
+ }
+ sorted_categories.at(pos) = iter->second;
+ }
+ decltype(sorted_categories)::iterator viter = sorted_categories.begin(), vend = sorted_categories.end();
+ for (; viter != vend; viter++)
+ if (viter->get())
+ Enable(*viter, Last);
+}
+
+void
+TypeCategoryMap::DisableAllCategories ()
+{
+ Mutex::Locker locker(m_map_mutex);
+ Position p = First;
+ for (; false == m_active_categories.empty(); p++)
+ {
+ m_active_categories.front()->SetEnabledPosition(p);
+ Disable(m_active_categories.front());
+ }
+}
+
+void
TypeCategoryMap::Clear ()
{
Mutex::Locker locker(m_map_mutex);
@@ -266,6 +306,34 @@ TypeCategoryMap::GetSyntheticChildren (ValueObject& valobj,
}
#endif
+lldb::TypeValidatorImplSP
+TypeCategoryMap::GetValidator (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
+{
+ Mutex::Locker locker(m_map_mutex);
+
+ uint32_t reason_why;
+ ActiveCategoriesIterator begin, end = m_active_categories.end();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+
+ FormattersMatchVector matches = FormatManager::GetPossibleMatches(valobj, use_dynamic);
+
+ for (begin = m_active_categories.begin(); begin != end; begin++)
+ {
+ lldb::TypeCategoryImplSP category_sp = *begin;
+ lldb::TypeValidatorImplSP current_format;
+ if (log)
+ log->Printf("\n[CategoryMap::GetValidator] Trying to use category %s", category_sp->GetName());
+ if (!category_sp->Get(valobj, matches, current_format, &reason_why))
+ continue;
+ return current_format;
+ }
+ if (log)
+ log->Printf("[CategoryMap::GetValidator] nothing found - returning empty SP");
+ return lldb::TypeValidatorImplSP();
+}
+
void
TypeCategoryMap::LoopThrough(CallbackType callback, void* param)
{
diff --git a/source/DataFormatters/TypeFormat.cpp b/source/DataFormatters/TypeFormat.cpp
index 0c62daf87bbc..f07d8127d2b9 100644
--- a/source/DataFormatters/TypeFormat.cpp
+++ b/source/DataFormatters/TypeFormat.cpp
@@ -59,9 +59,9 @@ TypeFormatImpl_Format::FormatObject (ValueObject *valobj,
{
if (!valobj)
return false;
- if (valobj->GetClangType().IsAggregateType () == false)
+ if (valobj->CanProvideValue())
{
- const Value& value(valobj->GetValue());
+ Value& value(valobj->GetValue());
const Value::ContextType context_type = value.GetContextType();
ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
DataExtractor data;
@@ -92,14 +92,14 @@ TypeFormatImpl_Format::FormatObject (ValueObject *valobj,
}
else
{
- ClangASTType clang_type = valobj->GetClangType ();
+ ClangASTType clang_type = value.GetClangType ();
if (clang_type)
{
// put custom bytes to display in the DataExtractor to override the default value logic
if (GetFormat() == eFormatCString)
{
lldb_private::Flags type_flags(clang_type.GetTypeInfo(NULL)); // disambiguate w.r.t. TypeFormatImpl::Flags
- if (type_flags.Test(ClangASTType::eTypeIsPointer) && !type_flags.Test(ClangASTType::eTypeIsObjC))
+ if (type_flags.Test(eTypeIsPointer) && !type_flags.Test(eTypeIsObjC))
{
// if we are dumping a pointer as a c-string, get the pointee data as a string
TargetSP target_sp(valobj->GetTargetSP());
@@ -180,7 +180,7 @@ TypeFormatImpl_EnumType::FormatObject (ValueObject *valobj,
dest.clear();
if (!valobj)
return false;
- if (valobj->GetClangType().IsAggregateType ())
+ if (!valobj->CanProvideValue())
return false;
ProcessSP process_sp;
TargetSP target_sp;
@@ -209,7 +209,7 @@ TypeFormatImpl_EnumType::FormatObject (ValueObject *valobj,
{
if (!type_sp)
continue;
- if ( (type_sp->GetClangForwardType().GetTypeInfo() & ClangASTType::eTypeIsEnumeration) == ClangASTType::eTypeIsEnumeration)
+ if ( (type_sp->GetClangForwardType().GetTypeInfo() & eTypeIsEnumeration) == eTypeIsEnumeration)
{
valobj_enum_type = type_sp->GetClangFullType();
m_types.emplace(valobj_key,valobj_enum_type);
diff --git a/source/DataFormatters/TypeSummary.cpp b/source/DataFormatters/TypeSummary.cpp
index e5d80174c3cc..ff089af58cb7 100644
--- a/source/DataFormatters/TypeSummary.cpp
+++ b/source/DataFormatters/TypeSummary.cpp
@@ -34,6 +34,50 @@
using namespace lldb;
using namespace lldb_private;
+TypeSummaryOptions::TypeSummaryOptions () :
+ m_lang(eLanguageTypeUnknown),
+ m_capping(eTypeSummaryCapped)
+{}
+
+TypeSummaryOptions::TypeSummaryOptions (const TypeSummaryOptions& rhs) :
+ m_lang(rhs.m_lang),
+ m_capping(rhs.m_capping)
+{}
+
+TypeSummaryOptions&
+TypeSummaryOptions::operator = (const TypeSummaryOptions& rhs)
+{
+ m_lang = rhs.m_lang;
+ m_capping = rhs.m_capping;
+ return *this;
+}
+
+lldb::LanguageType
+TypeSummaryOptions::GetLanguage () const
+{
+ return m_lang;
+}
+
+lldb::TypeSummaryCapping
+TypeSummaryOptions::GetCapping () const
+{
+ return m_capping;
+}
+
+TypeSummaryOptions&
+TypeSummaryOptions::SetLanguage (lldb::LanguageType lang)
+{
+ m_lang = lang;
+ return *this;
+}
+
+TypeSummaryOptions&
+TypeSummaryOptions::SetCapping (lldb::TypeSummaryCapping cap)
+{
+ m_capping = cap;
+ return *this;
+}
+
TypeSummaryImpl::TypeSummaryImpl (const TypeSummaryImpl::Flags& flags) :
m_flags(flags)
{
@@ -51,7 +95,8 @@ m_format()
bool
StringSummaryFormat::FormatObject (ValueObject *valobj,
- std::string& retval)
+ std::string& retval,
+ const TypeSummaryOptions& options)
{
if (!valobj)
{
@@ -115,11 +160,12 @@ m_description(description ? description : "")
bool
CXXFunctionSummaryFormat::FormatObject (ValueObject *valobj,
- std::string& dest)
+ std::string& dest,
+ const TypeSummaryOptions& options)
{
dest.clear();
StreamString stream;
- if (!m_impl || m_impl(*valobj,stream) == false)
+ if (!m_impl || m_impl(*valobj,stream,options) == false)
return false;
dest.assign(stream.GetData());
return true;
@@ -160,7 +206,8 @@ m_script_function_sp()
bool
ScriptSummaryFormat::FormatObject (ValueObject *valobj,
- std::string& retval)
+ std::string& retval,
+ const TypeSummaryOptions& options)
{
Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
@@ -190,6 +237,7 @@ ScriptSummaryFormat::FormatObject (ValueObject *valobj,
return script_interpreter->GetScriptedSummary(m_function_name.c_str(),
valobj->GetSP(),
m_script_function_sp,
+ options,
retval);
}
diff --git a/source/DataFormatters/TypeSynthetic.cpp b/source/DataFormatters/TypeSynthetic.cpp
index 3949673a4be8..13c1c7508b68 100644
--- a/source/DataFormatters/TypeSynthetic.cpp
+++ b/source/DataFormatters/TypeSynthetic.cpp
@@ -23,6 +23,7 @@
#include "lldb/Core/StreamString.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
@@ -30,6 +31,59 @@
using namespace lldb;
using namespace lldb_private;
+void
+TypeFilterImpl::AddExpressionPath (const std::string& path)
+{
+ bool need_add_dot = true;
+ if (path[0] == '.' ||
+ (path[0] == '-' && path[1] == '>') ||
+ path[0] == '[')
+ need_add_dot = false;
+ // add a '.' symbol to help forgetful users
+ if(!need_add_dot)
+ m_expression_paths.push_back(path);
+ else
+ m_expression_paths.push_back(std::string(".") + path);
+}
+
+bool
+TypeFilterImpl::SetExpressionPathAtIndex (size_t i, const std::string& path)
+{
+ if (i >= GetCount())
+ return false;
+ bool need_add_dot = true;
+ if (path[0] == '.' ||
+ (path[0] == '-' && path[1] == '>') ||
+ path[0] == '[')
+ need_add_dot = false;
+ // add a '.' symbol to help forgetful users
+ if(!need_add_dot)
+ m_expression_paths[i] = path;
+ else
+ m_expression_paths[i] = std::string(".") + path;
+ return true;
+}
+
+size_t
+TypeFilterImpl::FrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ const char* name_cstr = name.GetCString();
+ for (size_t i = 0; i < filter->GetCount(); i++)
+ {
+ const char* expr_cstr = filter->GetExpressionPathAtIndex(i);
+ if (expr_cstr)
+ {
+ if (*expr_cstr == '.')
+ expr_cstr++;
+ else if (*expr_cstr == '-' && *(expr_cstr+1) == '>')
+ expr_cstr += 2;
+ }
+ if (!::strcmp(name_cstr, expr_cstr))
+ return i;
+ }
+ return UINT32_MAX;
+}
+
std::string
TypeFilterImpl::GetDescription()
{
@@ -63,6 +117,41 @@ CXXSyntheticChildren::GetDescription()
return sstr.GetString();
}
+lldb::ValueObjectSP
+SyntheticChildrenFrontEnd::CreateValueObjectFromExpression (const char* name,
+ const char* expression,
+ const ExecutionContext& exe_ctx)
+{
+ ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromExpression(name, expression, exe_ctx));
+ if (valobj_sp)
+ valobj_sp->SetSyntheticChildrenGenerated(true);
+ return valobj_sp;
+}
+
+lldb::ValueObjectSP
+SyntheticChildrenFrontEnd::CreateValueObjectFromAddress (const char* name,
+ uint64_t address,
+ const ExecutionContext& exe_ctx,
+ ClangASTType type)
+{
+ ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromAddress(name, address, exe_ctx, type));
+ if (valobj_sp)
+ valobj_sp->SetSyntheticChildrenGenerated(true);
+ return valobj_sp;
+}
+
+lldb::ValueObjectSP
+SyntheticChildrenFrontEnd::CreateValueObjectFromData (const char* name,
+ const DataExtractor& data,
+ const ExecutionContext& exe_ctx,
+ ClangASTType type)
+{
+ ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromData(name, data, exe_ctx, type));
+ if (valobj_sp)
+ valobj_sp->SetSyntheticChildrenGenerated(true);
+ return valobj_sp;
+}
+
#ifndef LLDB_DISABLE_PYTHON
ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass, ValueObject &backend) :
@@ -98,6 +187,55 @@ ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex (size_t idx)
return m_interpreter->GetChildAtIndex(m_wrapper_sp, idx);
}
+bool
+ScriptedSyntheticChildren::FrontEnd::IsValid ()
+{
+ return m_wrapper_sp.get() != nullptr && m_wrapper_sp->operator bool() && m_interpreter != nullptr;
+}
+
+size_t
+ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren ()
+{
+ if (!m_wrapper_sp || m_interpreter == NULL)
+ return 0;
+ return m_interpreter->CalculateNumChildren(m_wrapper_sp);
+}
+
+bool
+ScriptedSyntheticChildren::FrontEnd::Update ()
+{
+ if (!m_wrapper_sp || m_interpreter == NULL)
+ return false;
+
+ return m_interpreter->UpdateSynthProviderInstance(m_wrapper_sp);
+}
+
+bool
+ScriptedSyntheticChildren::FrontEnd::MightHaveChildren ()
+{
+ if (!m_wrapper_sp || m_interpreter == NULL)
+ return false;
+
+ return m_interpreter->MightHaveChildrenSynthProviderInstance(m_wrapper_sp);
+}
+
+size_t
+ScriptedSyntheticChildren::FrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (!m_wrapper_sp || m_interpreter == NULL)
+ return UINT32_MAX;
+ return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp, name.GetCString());
+}
+
+lldb::ValueObjectSP
+ScriptedSyntheticChildren::FrontEnd::GetSyntheticValue ()
+{
+ if (!m_wrapper_sp || m_interpreter == NULL)
+ return nullptr;
+
+ return m_interpreter->GetSyntheticValue(m_wrapper_sp);
+}
+
std::string
ScriptedSyntheticChildren::GetDescription()
{
diff --git a/source/DataFormatters/TypeValidator.cpp b/source/DataFormatters/TypeValidator.cpp
new file mode 100644
index 000000000000..b5efac8f586a
--- /dev/null
+++ b/source/DataFormatters/TypeValidator.cpp
@@ -0,0 +1,75 @@
+//===-- TypeValidator.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+
+// C++ Includes
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/DataFormatters/TypeValidator.h"
+#include "lldb/Core/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TypeValidatorImpl::TypeValidatorImpl(const Flags &flags) :
+ m_flags(flags),
+ m_my_revision(0)
+{
+}
+
+TypeValidatorImpl::~TypeValidatorImpl()
+{
+}
+
+TypeValidatorImpl::ValidationResult
+TypeValidatorImpl::Success ()
+{
+ return ValidationResult { TypeValidatorResult::Success, "" };
+}
+
+TypeValidatorImpl::ValidationResult
+TypeValidatorImpl::Failure (std::string message)
+{
+ return ValidationResult { TypeValidatorResult::Failure, message };
+}
+
+TypeValidatorImpl_CXX::TypeValidatorImpl_CXX (ValidatorFunction f, std::string d, const TypeValidatorImpl::Flags& flags) :
+ TypeValidatorImpl(flags),
+ m_description(d),
+ m_validator_function(f)
+{
+}
+
+TypeValidatorImpl_CXX::~TypeValidatorImpl_CXX()
+{
+}
+
+TypeValidatorImpl::ValidationResult
+TypeValidatorImpl_CXX::FormatObject (ValueObject *valobj) const
+{
+ if (!valobj)
+ return Success(); // I guess there's nothing wrong with a null valueobject..
+
+ return m_validator_function(valobj);
+}
+
+std::string
+TypeValidatorImpl_CXX::GetDescription()
+{
+ StreamString sstr;
+ sstr.Printf ("%s%s%s%s",
+ m_description.c_str(),
+ Cascades() ? "" : " (not cascading)",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "");
+ return sstr.GetString();
+}
diff --git a/source/DataFormatters/ValueObjectPrinter.cpp b/source/DataFormatters/ValueObjectPrinter.cpp
index 65e5e3f45823..5560ce2971e7 100644
--- a/source/DataFormatters/ValueObjectPrinter.cpp
+++ b/source/DataFormatters/ValueObjectPrinter.cpp
@@ -66,11 +66,13 @@ ValueObjectPrinter::Init (ValueObject* valobj,
bool
ValueObjectPrinter::PrintValueObject ()
{
- if (!GetDynamicValueIfNeeded () || m_valobj == nullptr)
+ if (!GetMostSpecializedValue () || m_valobj == nullptr)
return false;
if (ShouldPrintValueObject())
{
+ PrintValidationMarkerIfNeeded();
+
PrintLocationIfNeeded();
m_stream->Indent();
@@ -89,11 +91,13 @@ ValueObjectPrinter::PrintValueObject ()
else
m_stream->EOL();
+ PrintValidationErrorIfNeeded();
+
return true;
}
bool
-ValueObjectPrinter::GetDynamicValueIfNeeded ()
+ValueObjectPrinter::GetMostSpecializedValue ()
{
if (m_valobj)
return true;
@@ -130,6 +134,25 @@ ValueObjectPrinter::GetDynamicValueIfNeeded ()
else
m_valobj = m_orig_valobj;
}
+
+ if (m_valobj->IsSynthetic())
+ {
+ if (options.m_use_synthetic == false)
+ {
+ ValueObject *non_synthetic = m_valobj->GetNonSyntheticValue().get();
+ if (non_synthetic)
+ m_valobj = non_synthetic;
+ }
+ }
+ else
+ {
+ if (options.m_use_synthetic == true)
+ {
+ ValueObject *synthetic = m_valobj->GetSyntheticValue().get();
+ if (synthetic)
+ m_valobj = synthetic;
+ }
+ }
}
m_clang_type = m_valobj->GetClangType();
m_type_flags = m_clang_type.GetTypeInfo ();
@@ -160,7 +183,7 @@ bool
ValueObjectPrinter::ShouldPrintValueObject ()
{
if (m_should_print == eLazyBoolCalculate)
- m_should_print = (options.m_flat_output == false || m_type_flags.Test (ClangASTType::eTypeHasValue)) ? eLazyBoolYes : eLazyBoolNo;
+ m_should_print = (options.m_flat_output == false || m_type_flags.Test (eTypeHasValue)) ? eLazyBoolYes : eLazyBoolNo;
return m_should_print == eLazyBoolYes;
}
@@ -176,7 +199,7 @@ bool
ValueObjectPrinter::IsPtr ()
{
if (m_is_ptr == eLazyBoolCalculate)
- m_is_ptr = m_type_flags.Test (ClangASTType::eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo;
+ m_is_ptr = m_type_flags.Test (eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo;
return m_is_ptr == eLazyBoolYes;
}
@@ -184,7 +207,7 @@ bool
ValueObjectPrinter::IsRef ()
{
if (m_is_ref == eLazyBoolCalculate)
- m_is_ref = m_type_flags.Test (ClangASTType::eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo;
+ m_is_ref = m_type_flags.Test (eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo;
return m_is_ref == eLazyBoolYes;
}
@@ -192,7 +215,7 @@ bool
ValueObjectPrinter::IsAggregate ()
{
if (m_is_aggregate == eLazyBoolCalculate)
- m_is_aggregate = m_type_flags.Test (ClangASTType::eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo;
+ m_is_aggregate = m_type_flags.Test (eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo;
return m_is_aggregate == eLazyBoolYes;
}
@@ -222,13 +245,13 @@ ValueObjectPrinter::PrintTypeIfNeeded ()
{
// Some ValueObjects don't have types (like registers sets). Only print
// the type if there is one to print
- ConstString qualified_type_name;
- if (options.m_be_raw)
- qualified_type_name = m_valobj->GetQualifiedTypeName();
+ ConstString type_name;
+ if (options.m_use_type_display_name)
+ type_name = m_valobj->GetDisplayTypeName();
else
- qualified_type_name = m_valobj->GetDisplayTypeName();
- if (qualified_type_name)
- m_stream->Printf("(%s) ", qualified_type_name.GetCString());
+ type_name = m_valobj->GetQualifiedTypeName();
+ if (type_name)
+ m_stream->Printf("(%s) ", type_name.GetCString());
else
show_type = false;
}
@@ -438,8 +461,7 @@ ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description,
ValueObject*
ValueObjectPrinter::GetValueObjectForChildrenGeneration ()
{
- ValueObjectSP synth_valobj_sp = m_valobj->GetSyntheticValue (options.m_use_synthetic);
- return (synth_valobj_sp ? synth_valobj_sp.get() : m_valobj);
+ return m_valobj;
}
void
@@ -536,7 +558,13 @@ ValueObjectPrinter::PrintChildren (uint32_t curr_ptr_depth)
{
// Aggregate, no children...
if (ShouldPrintValueObject())
- m_stream->PutCString(" {}\n");
+ {
+ // if it has a synthetic value, then don't print {}, the synthetic children are probably only being used to vend a value
+ if (m_valobj->DoesProvideSyntheticValue())
+ m_stream->PutCString( "\n");
+ else
+ m_stream->PutCString(" {}\n");
+ }
}
else
{
@@ -548,7 +576,7 @@ ValueObjectPrinter::PrintChildren (uint32_t curr_ptr_depth)
bool
ValueObjectPrinter::PrintChildrenOneLiner (bool hide_names)
{
- if (!GetDynamicValueIfNeeded () || m_valobj == nullptr)
+ if (!GetMostSpecializedValue () || m_valobj == nullptr)
return false;
ValueObject* synth_m_valobj = GetValueObjectForChildrenGeneration();
@@ -563,9 +591,8 @@ ValueObjectPrinter::PrintChildrenOneLiner (bool hide_names)
for (uint32_t idx=0; idx<num_children; ++idx)
{
lldb::ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true));
- lldb::ValueObjectSP child_dyn_sp = child_sp.get() ? child_sp->GetDynamicValue(options.m_use_dynamic) : child_sp;
- if (child_dyn_sp)
- child_sp = child_dyn_sp;
+ if (child_sp)
+ child_sp = child_sp->GetQualifiedRepresentationIfAvailable(options.m_use_dynamic, options.m_use_synthetic);
if (child_sp)
{
if (idx)
@@ -604,7 +631,7 @@ 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_be_raw) ? false : DataVisualization::ShouldPrintAsOneLiner(*m_valobj);
+ bool print_oneline = (curr_ptr_depth > 0 || options.m_show_types || !options.m_allow_oneliner_mode) ? false : DataVisualization::ShouldPrintAsOneLiner(*m_valobj);
if (print_children)
{
@@ -624,3 +651,44 @@ ValueObjectPrinter::PrintChildrenIfNeeded (bool value_printed,
else
m_stream->EOL();
}
+
+bool
+ValueObjectPrinter::ShouldPrintValidation ()
+{
+ return options.m_run_validator;
+}
+
+bool
+ValueObjectPrinter::PrintValidationMarkerIfNeeded ()
+{
+ if (!ShouldPrintValidation())
+ return false;
+
+ m_validation = m_valobj->GetValidationStatus();
+
+ if (TypeValidatorResult::Failure == m_validation.first)
+ {
+ m_stream->Printf("! ");
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ValueObjectPrinter::PrintValidationErrorIfNeeded ()
+{
+ if (!ShouldPrintValidation())
+ return false;
+
+ if (TypeValidatorResult::Success == m_validation.first)
+ return false;
+
+ if (m_validation.second.empty())
+ m_validation.second.assign("unknown error");
+
+ m_stream->Printf(" ! validation error: %s", m_validation.second.c_str());
+ m_stream->EOL();
+
+ return true;
+}
diff --git a/source/Expression/ClangASTSource.cpp b/source/Expression/ClangASTSource.cpp
index d488993b90d7..9a6d6e532255 100644
--- a/source/Expression/ClangASTSource.cpp
+++ b/source/Expression/ClangASTSource.cpp
@@ -708,6 +708,8 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
else
m_target->GetImages().FindTypes(null_sc, name, exact_match, 1, types);
+ bool found_a_type = false;
+
if (types.GetSize())
{
lldb::TypeSP type_sp = types.GetTypeAtIndex(0);
@@ -736,8 +738,62 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
}
context.AddTypeDecl(copied_clang_type);
+
+ found_a_type = true;
}
- else
+
+ if (!found_a_type)
+ {
+ // 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;
+
+ if (log)
+ {
+ log->Printf(" CAS::FEVD[%u] Matching entity found for \"%s\" in the modules",
+ current_id,
+ name.GetCString());
+ }
+
+ clang::NamedDecl *const decl_from_modules = decls[0];
+
+ if (llvm::isa<clang::TypeDecl>(decl_from_modules) ||
+ llvm::isa<clang::ObjCContainerDecl>(decl_from_modules) ||
+ llvm::isa<clang::EnumConstantDecl>(decl_from_modules))
+ {
+ clang::Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, &decl_from_modules->getASTContext(), decl_from_modules);
+ clang::NamedDecl *copied_named_decl = copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr;
+
+ if (!copied_named_decl)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a type from the modules",
+ current_id);
+
+ break;
+ }
+
+ context.AddNamedDecl(copied_named_decl);
+
+ found_a_type = true;
+ }
+ }
+ } while (0);
+ }
+
+ if (!found_a_type)
{
do
{
@@ -753,19 +809,19 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
if (!language_runtime)
break;
- TypeVendor *type_vendor = language_runtime->GetTypeVendor();
+ DeclVendor *decl_vendor = language_runtime->GetDeclVendor();
- if (!type_vendor)
+ if (!decl_vendor)
break;
bool append = false;
uint32_t max_matches = 1;
- std::vector <ClangASTType> types;
+ std::vector <clang::NamedDecl *> decls;
- if (!type_vendor->FindTypes(name,
+ if (!decl_vendor->FindDecls(name,
append,
max_matches,
- types))
+ decls))
break;
if (log)
@@ -774,10 +830,11 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
current_id,
name.GetCString());
}
-
- ClangASTType copied_clang_type (GuardedCopyType(types[0]));
-
- if (!copied_clang_type)
+
+ clang::Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, &decls[0]->getASTContext(), decls[0]);
+ clang::NamedDecl *copied_named_decl = copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr;
+
+ if (!copied_named_decl)
{
if (log)
log->Printf(" CAS::FEVD[%u] - Couldn't export a type from the runtime",
@@ -786,7 +843,7 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
break;
}
- context.AddTypeDecl(copied_clang_type);
+ context.AddNamedDecl(copied_named_decl);
}
while(0);
}
@@ -895,31 +952,44 @@ FindObjCMethodDeclsWithOrigin (unsigned int current_id,
}
DeclarationName original_decl_name(original_selector);
-
- ObjCInterfaceDecl::lookup_result result = original_interface_decl->lookup(original_decl_name);
-
- if (result.empty())
- return false;
-
- if (!result[0])
+
+ llvm::SmallVector<NamedDecl *, 1> methods;
+
+ ClangASTContext::GetCompleteDecl(original_ctx, original_interface_decl);
+
+ if (ObjCMethodDecl *instance_method_decl = original_interface_decl->lookupInstanceMethod(original_selector))
+ {
+ methods.push_back(instance_method_decl);
+ }
+ else if (ObjCMethodDecl *class_method_decl = original_interface_decl->lookupClassMethod(original_selector))
+ {
+ methods.push_back(class_method_decl);
+ }
+
+ if (methods.empty())
+ {
return false;
-
- for (NamedDecl *named_decl : result)
+ }
+
+ for (NamedDecl *named_decl : methods)
{
+ if (!named_decl)
+ continue;
+
ObjCMethodDecl *result_method = dyn_cast<ObjCMethodDecl>(named_decl);
if (!result_method)
- return false;
+ continue;
Decl *copied_decl = ast_importer->CopyDecl(ast_context, &result_method->getASTContext(), result_method);
if (!copied_decl)
- return false;
+ continue;
ObjCMethodDecl *copied_method_decl = dyn_cast<ObjCMethodDecl>(copied_decl);
if (!copied_method_decl)
- return false;
+ continue;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@@ -1169,10 +1239,43 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
return;
}
while (0);
+
+ do
+ {
+ // Check the modules only if the debug information didn't have a complete interface.
+
+ if (ClangModulesDeclVendor *modules_decl_vendor = m_target->GetClangModulesDeclVendor())
+ {
+ ConstString interface_name(interface_decl->getNameAsString().c_str());
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <clang::NamedDecl *> decls;
+
+ if (!modules_decl_vendor->FindDecls(interface_name,
+ append,
+ max_matches,
+ decls))
+ break;
+
+ ObjCInterfaceDecl *interface_decl_from_modules = dyn_cast<ObjCInterfaceDecl>(decls[0]);
+
+ if (!interface_decl_from_modules)
+ break;
+
+ if (FindObjCMethodDeclsWithOrigin(current_id,
+ context,
+ interface_decl_from_modules,
+ m_ast_context,
+ m_ast_importer,
+ "in modules"))
+ return;
+ }
+ }
+ while (0);
do
{
- // Check the runtime only if the debug information didn't have a complete interface.
+ // Check the runtime only if the debug information didn't have a complete interface and the modules don't get us anywhere.
lldb::ProcessSP process(m_target->GetProcessSP());
@@ -1184,31 +1287,27 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
if (!language_runtime)
break;
- TypeVendor *type_vendor = language_runtime->GetTypeVendor();
+ DeclVendor *decl_vendor = language_runtime->GetDeclVendor();
- if (!type_vendor)
+ if (!decl_vendor)
break;
ConstString interface_name(interface_decl->getNameAsString().c_str());
bool append = false;
uint32_t max_matches = 1;
- std::vector <ClangASTType> types;
+ std::vector <clang::NamedDecl *> decls;
- if (!type_vendor->FindTypes(interface_name,
+ if (!decl_vendor->FindDecls(interface_name,
append,
max_matches,
- types))
+ decls))
break;
- const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();
-
- const ObjCInterfaceType *runtime_interface_type = dyn_cast<ObjCInterfaceType>(runtime_clang_type);
-
- if (!runtime_interface_type)
+ ObjCInterfaceDecl *runtime_interface_decl = dyn_cast<ObjCInterfaceDecl>(decls[0]);
+
+ if (!runtime_interface_decl)
break;
- ObjCInterfaceDecl *runtime_interface_decl = runtime_interface_type->getDecl();
-
FindObjCMethodDeclsWithOrigin(current_id,
context,
runtime_interface_decl,
@@ -1339,10 +1438,50 @@ ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context)
return;
}
while(0);
+
+ do
+ {
+ // Check the modules only if the debug information didn't have a complete interface.
+
+ ClangModulesDeclVendor *modules_decl_vendor = m_target->GetClangModulesDeclVendor();
+
+ if (!modules_decl_vendor)
+ break;
+
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <clang::NamedDecl *> decls;
+
+ if (!modules_decl_vendor->FindDecls(class_name,
+ append,
+ max_matches,
+ decls))
+ break;
+
+ DeclFromUser<const ObjCInterfaceDecl> interface_decl_from_modules(dyn_cast<ObjCInterfaceDecl>(decls[0]));
+
+ if (!interface_decl_from_modules.IsValid())
+ break;
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] trying module (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
+ current_id,
+ static_cast<const void*>(interface_decl_from_modules.decl),
+ static_cast<void*>(&interface_decl_from_modules->getASTContext()));
+
+ if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer,
+ interface_decl_from_modules))
+ return;
+ }
+ while(0);
do
{
- // Check the runtime only if the debug information didn't have a complete interface.
+ // Check the runtime only if the debug information didn't have a complete interface
+ // and nothing was in the modules.
lldb::ProcessSP process(m_target->GetProcessSP());
@@ -1354,41 +1493,37 @@ ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context)
if (!language_runtime)
return;
- TypeVendor *type_vendor = language_runtime->GetTypeVendor();
+ DeclVendor *decl_vendor = language_runtime->GetDeclVendor();
- if (!type_vendor)
+ if (!decl_vendor)
break;
bool append = false;
uint32_t max_matches = 1;
- std::vector <ClangASTType> types;
+ std::vector <clang::NamedDecl *> decls;
- if (!type_vendor->FindTypes(class_name,
+ if (!decl_vendor->FindDecls(class_name,
append,
max_matches,
- types))
+ decls))
break;
- const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();
-
- const ObjCInterfaceType *runtime_interface_type = dyn_cast<ObjCInterfaceType>(runtime_clang_type);
-
- if (!runtime_interface_type)
+ DeclFromUser<const ObjCInterfaceDecl> interface_decl_from_runtime(dyn_cast<ObjCInterfaceDecl>(decls[0]));
+
+ if (!interface_decl_from_runtime.IsValid())
break;
- DeclFromUser<const ObjCInterfaceDecl> runtime_iface_decl(runtime_interface_type->getDecl());
-
if (log)
log->Printf("CAS::FOPD[%d] trying runtime (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
current_id,
- static_cast<const void*>(runtime_iface_decl.decl),
- static_cast<void*>(&runtime_iface_decl->getASTContext()));
+ static_cast<const void*>(interface_decl_from_runtime.decl),
+ static_cast<void*>(&interface_decl_from_runtime->getASTContext()));
if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
context,
*m_ast_context,
m_ast_importer,
- runtime_iface_decl))
+ interface_decl_from_runtime))
return;
}
while(0);
diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp
index 43c8a5fb1bcb..e3027378422f 100644
--- a/source/Expression/ClangExpressionDeclMap.cpp
+++ b/source/Expression/ClangExpressionDeclMap.cpp
@@ -36,6 +36,7 @@
#include "lldb/Symbol/TypeList.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
@@ -543,6 +544,7 @@ ClangExpressionDeclMap::GetFunctionAddress
FindCodeSymbolInContext(name, m_parser_vars->m_sym_ctx, sc_list);
uint32_t sc_list_size = sc_list.GetSize();
+
if (sc_list_size == 0)
{
// We occasionally get debug information in which a const function is reported
@@ -562,6 +564,25 @@ 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();
+ }
+ }
for (uint32_t i=0; i<sc_list_size; ++i)
{
@@ -1274,10 +1295,9 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
{
valobj = frame->GetValueForVariableExpressionPath(name_unique_cstr,
eNoDynamicValues,
- StackFrame::eExpressionPathOptionCheckPtrVsMember ||
- StackFrame::eExpressionPathOptionsAllowDirectIVarAccess ||
- StackFrame::eExpressionPathOptionsNoFragileObjcIvar ||
- StackFrame::eExpressionPathOptionsNoSyntheticChildren ||
+ StackFrame::eExpressionPathOptionCheckPtrVsMember |
+ StackFrame::eExpressionPathOptionsNoFragileObjcIvar |
+ StackFrame::eExpressionPathOptionsNoSyntheticChildren |
StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
var,
err);
@@ -1307,6 +1327,16 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
return;
}
}
+
+ std::vector<clang::NamedDecl *> decls_from_modules;
+
+ if (target)
+ {
+ if (ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor())
+ {
+ decl_vendor->FindDecls(name, false, UINT32_MAX, decls_from_modules);
+ }
+ }
if (!context.m_found.variable)
{
@@ -1384,6 +1414,19 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
non_extern_symbol = sym_ctx.symbol;
}
}
+
+ if (!context.m_found.function_with_type_info)
+ {
+ for (clang::NamedDecl *decl : decls_from_modules)
+ {
+ if (llvm::isa<clang::FunctionDecl>(decl))
+ {
+ clang::NamedDecl *copied_decl = llvm::cast<FunctionDecl>(m_ast_importer->CopyDecl(m_ast_context, &decl->getASTContext(), decl));
+ context.AddNamedDecl(copied_decl);
+ context.m_found.function_with_type_info = true;
+ }
+ }
+ }
if (!context.m_found.function_with_type_info)
{
diff --git a/source/Expression/ClangExpressionParser.cpp b/source/Expression/ClangExpressionParser.cpp
index f32ca3ae216c..4906108401af 100644
--- a/source/Expression/ClangExpressionParser.cpp
+++ b/source/Expression/ClangExpressionParser.cpp
@@ -22,6 +22,7 @@
#include "lldb/Expression/ClangASTSource.h"
#include "lldb/Expression/ClangExpression.h"
#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/ClangModulesDeclVendor.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Expression/IRInterpreter.h"
@@ -92,6 +93,47 @@ std::string GetBuiltinIncludePath(const char *Argv0) {
return P.str();
}
+class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks
+{
+ ClangModulesDeclVendor &m_decl_vendor;
+ StreamString m_error_stream;
+ bool m_has_errors = false;
+public:
+ LLDBPreprocessorCallbacks(ClangModulesDeclVendor &decl_vendor) :
+ m_decl_vendor(decl_vendor)
+ {
+ }
+
+ virtual void moduleImport(SourceLocation import_location,
+ ModuleIdPath path,
+ const clang::Module * /*null*/)
+ {
+ std::vector<llvm::StringRef> string_path;
+
+ for (const std::pair<IdentifierInfo *, SourceLocation> &component : path)
+ {
+ string_path.push_back(component.first->getName());
+ }
+
+ StreamString error_stream;
+
+ if (!m_decl_vendor.AddModule(string_path, m_error_stream))
+ {
+ m_has_errors = true;
+ }
+ }
+
+ bool hasErrors()
+ {
+ return m_has_errors;
+ }
+
+ const std::string &getErrorString()
+ {
+ return m_error_stream.GetString();
+ }
+};
+
//===----------------------------------------------------------------------===//
// Implementation of ClangExpressionParser
//===----------------------------------------------------------------------===//
@@ -101,7 +143,8 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
bool generate_debug_info) :
m_expr (expr),
m_compiler (),
- m_code_generator ()
+ m_code_generator (),
+ m_pp_callbacks(nullptr)
{
// 1. Create a new compiler instance.
m_compiler.reset(new CompilerInstance());
@@ -165,6 +208,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
case lldb::eLanguageTypeC_plus_plus:
m_compiler->getLangOpts().CPlusPlus = true;
m_compiler->getLangOpts().CPlusPlus11 = true;
+ m_compiler->getHeaderSearchOpts().UseLibcxx = true;
break;
case lldb::eLanguageTypeObjC_plus_plus:
default:
@@ -172,6 +216,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
m_compiler->getLangOpts().ObjC2 = true;
m_compiler->getLangOpts().CPlusPlus = true;
m_compiler->getLangOpts().CPlusPlus11 = true;
+ m_compiler->getHeaderSearchOpts().UseLibcxx = true;
break;
}
@@ -246,7 +291,14 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
m_compiler->createFileManager();
m_compiler->createPreprocessor(TU_Complete);
-
+
+ if (ClangModulesDeclVendor *decl_vendor = target_sp->GetClangModulesDeclVendor())
+ {
+ std::unique_ptr<PPCallbacks> pp_callbacks(new LLDBPreprocessorCallbacks(*decl_vendor));
+ m_pp_callbacks = static_cast<LLDBPreprocessorCallbacks*>(pp_callbacks.get());
+ m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks));
+ }
+
// 6. Most of this we get from the CompilerInstance, but we
// also want to give the context an ExternalASTSource.
m_selector_table.reset(new SelectorTable());
@@ -257,6 +309,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
m_compiler->getPreprocessor().getIdentifierTable(),
*m_selector_table.get(),
*m_builtin_context.get()));
+
ast_context->InitBuiltinTypes(m_compiler->getTarget());
ClangExpressionDeclMap *decl_map = m_expr.DeclMap();
@@ -299,22 +352,23 @@ ClangExpressionParser::Parse (Stream &stream)
{
std::string temp_source_path;
+ int temp_fd = -1;
+ llvm::SmallString<PATH_MAX> result_path;
FileSpec tmpdir_file_spec;
if (HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
{
- tmpdir_file_spec.AppendPathComponent("expr.XXXXXX");
+ tmpdir_file_spec.AppendPathComponent("lldb-%%%%%%.expr");
temp_source_path = std::move(tmpdir_file_spec.GetPath());
+ llvm::sys::fs::createUniqueFile(temp_source_path, temp_fd, result_path);
}
else
{
- temp_source_path = "/tmp/expr.XXXXXX";
+ llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path);
}
-
- if (mktemp(&temp_source_path[0]))
+
+ if (temp_fd != -1)
{
- lldb_private::File file (temp_source_path.c_str(),
- File::eOpenOptionWrite | File::eOpenOptionCanCreateNewOnly,
- lldb::eFilePermissionsFileDefault);
+ lldb_private::File file (temp_fd, true);
const size_t expr_text_len = strlen(expr_text);
size_t bytes_written = expr_text_len;
if (file.Write(expr_text, bytes_written).Success())
@@ -323,7 +377,7 @@ ClangExpressionParser::Parse (Stream &stream)
{
file.Close();
SourceMgr.setMainFileID(SourceMgr.createFileID(
- m_file_manager->getFile(temp_source_path),
+ m_file_manager->getFile(result_path),
SourceLocation(), SrcMgr::C_User));
created_main_file = true;
}
@@ -351,14 +405,19 @@ ClangExpressionParser::Parse (Stream &stream)
TextDiagnosticBuffer::const_iterator diag_iterator;
int num_errors = 0;
+
+ if (m_pp_callbacks && m_pp_callbacks->hasErrors())
+ {
+ num_errors++;
+
+ stream.PutCString(m_pp_callbacks->getErrorString().c_str());
+ }
for (diag_iterator = diag_buf->warn_begin();
diag_iterator != diag_buf->warn_end();
++diag_iterator)
stream.Printf("warning: %s\n", (*diag_iterator).second.c_str());
- num_errors = 0;
-
for (diag_iterator = diag_buf->err_begin();
diag_iterator != diag_buf->err_end();
++diag_iterator)
diff --git a/source/Expression/ClangExpressionVariable.cpp b/source/Expression/ClangExpressionVariable.cpp
index c3eae41473e9..e86016e53a7d 100644
--- a/source/Expression/ClangExpressionVariable.cpp
+++ b/source/Expression/ClangExpressionVariable.cpp
@@ -28,6 +28,17 @@ ClangExpressionVariable::ClangExpressionVariable(ExecutionContextScope *exe_scop
{
}
+ClangExpressionVariable::ClangExpressionVariable (ExecutionContextScope *exe_scope,
+ Value &value,
+ const ConstString &name,
+ uint16_t flags) :
+ m_parser_vars(),
+ m_jit_vars (),
+ m_flags (flags),
+ m_frozen_sp (ValueObjectConstResult::Create (exe_scope, value, name))
+{
+}
+
ClangExpressionVariable::ClangExpressionVariable (const lldb::ValueObjectSP &valobj_sp) :
m_parser_vars(),
m_jit_vars (),
diff --git a/source/Expression/ClangFunction.cpp b/source/Expression/ClangFunction.cpp
index 27afba2898ab..b438dacdfabc 100644
--- a/source/Expression/ClangFunction.cpp
+++ b/source/Expression/ClangFunction.cpp
@@ -57,8 +57,8 @@ ClangFunction::ClangFunction
const ValueList &arg_value_list,
const char *name
) :
- m_parser(),
m_execution_unit_sp(),
+ m_parser(),
m_jit_module_wp(),
m_name (name ? name : "<unknown>"),
m_function_ptr (NULL),
@@ -422,7 +422,7 @@ ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_add
return true;
}
-ThreadPlan *
+lldb::ThreadPlanSP
ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
lldb::addr_t args_addr,
const EvaluateExpressionOptions &options,
@@ -447,14 +447,14 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
lldb::addr_t args = { args_addr };
- ThreadPlan *new_plan = new ThreadPlanCallFunction (*thread,
+ lldb::ThreadPlanSP new_plan_sp (new ThreadPlanCallFunction (*thread,
wrapper_address,
ClangASTType(),
args,
- options);
- new_plan->SetIsMasterPlan(true);
- new_plan->SetOkayToDiscard (false);
- return new_plan;
+ options));
+ new_plan_sp->SetIsMasterPlan(true);
+ new_plan_sp->SetOkayToDiscard (false);
+ return new_plan_sp;
}
bool
@@ -541,10 +541,10 @@ ClangFunction::ExecuteFunction(
if (log)
log->Printf("== [ClangFunction::ExecuteFunction] Executing function \"%s\" ==", m_name.c_str());
- lldb::ThreadPlanSP call_plan_sp (GetThreadPlanToCallFunction (exe_ctx,
- args_addr,
- real_options,
- errors));
+ lldb::ThreadPlanSP call_plan_sp = GetThreadPlanToCallFunction (exe_ctx,
+ args_addr,
+ real_options,
+ errors);
if (!call_plan_sp)
return lldb::eExpressionSetupError;
diff --git a/source/Expression/ClangModulesDeclVendor.cpp b/source/Expression/ClangModulesDeclVendor.cpp
new file mode 100644
index 000000000000..46adaaff33ce
--- /dev/null
+++ b/source/Expression/ClangModulesDeclVendor.cpp
@@ -0,0 +1,372 @@
+//===-- ClangModulesDeclVendor.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/ClangModulesDeclVendor.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Target.h"
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Serialization/ASTReader.h"
+
+#include <mutex>
+
+using namespace lldb_private;
+
+namespace {
+ // Any Clang compiler requires a consumer for diagnostics. This one stores them as strings
+ // so we can provide them to the user in case a module failed to load.
+ class StoringDiagnosticConsumer : public clang::DiagnosticConsumer
+ {
+ public:
+ StoringDiagnosticConsumer ();
+ void
+ HandleDiagnostic (clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info);
+
+ void
+ ClearDiagnostics ();
+
+ void
+ DumpDiagnostics (Stream &error_stream);
+ private:
+ typedef std::pair<clang::DiagnosticsEngine::Level, std::string> IDAndDiagnostic;
+ std::vector<IDAndDiagnostic> m_diagnostics;
+ Log * m_log;
+ };
+
+ // The private implementation of our ClangModulesDeclVendor. Contains all the Clang state required
+ // to load modules.
+ class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor
+ {
+ public:
+ ClangModulesDeclVendorImpl(llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> &diagnostics_engine,
+ llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> &compiler_invocation,
+ std::unique_ptr<clang::CompilerInstance> &&compiler_instance,
+ std::unique_ptr<clang::Parser> &&parser);
+
+ virtual bool
+ AddModule(std::vector<llvm::StringRef> &path,
+ Stream &error_stream);
+
+ virtual uint32_t
+ FindDecls (const ConstString &name,
+ bool append,
+ uint32_t max_matches,
+ std::vector <clang::NamedDecl*> &decls);
+
+ ~ClangModulesDeclVendorImpl();
+
+ private:
+ clang::ModuleLoadResult
+ DoGetModule(clang::ModuleIdPath path, bool make_visible);
+
+ 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;
+ };
+}
+
+StoringDiagnosticConsumer::StoringDiagnosticConsumer ()
+{
+ m_log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
+}
+
+void
+StoringDiagnosticConsumer::HandleDiagnostic (clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info)
+{
+ llvm::SmallVector<char, 256> diagnostic_string;
+
+ info.FormatDiagnostic(diagnostic_string);
+
+ m_diagnostics.push_back(IDAndDiagnostic(DiagLevel, std::string(diagnostic_string.data(), diagnostic_string.size())));
+}
+
+void
+StoringDiagnosticConsumer::ClearDiagnostics ()
+{
+ m_diagnostics.clear();
+}
+
+void
+StoringDiagnosticConsumer::DumpDiagnostics (Stream &error_stream)
+{
+ for (IDAndDiagnostic &diag : m_diagnostics)
+ {
+ switch (diag.first)
+ {
+ default:
+ error_stream.PutCString(diag.second.c_str());
+ error_stream.PutChar('\n');
+ break;
+ case clang::DiagnosticsEngine::Level::Ignored:
+ break;
+ }
+ }
+}
+
+static FileSpec
+GetResourceDir ()
+{
+ static FileSpec g_cached_resource_dir;
+
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, [](){
+ HostInfo::GetLLDBPath (lldb::ePathTypeClangDir, g_cached_resource_dir);
+ });
+
+ return g_cached_resource_dir;
+}
+
+
+ClangModulesDeclVendor::ClangModulesDeclVendor()
+{
+}
+
+ClangModulesDeclVendor::~ClangModulesDeclVendor()
+{
+}
+
+ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl(llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> &diagnostics_engine,
+ llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> &compiler_invocation,
+ std::unique_ptr<clang::CompilerInstance> &&compiler_instance,
+ std::unique_ptr<clang::Parser> &&parser) :
+ ClangModulesDeclVendor(),
+ m_diagnostics_engine(diagnostics_engine),
+ m_compiler_invocation(compiler_invocation),
+ m_compiler_instance(std::move(compiler_instance)),
+ m_parser(std::move(parser))
+{
+}
+
+bool
+ClangModulesDeclVendorImpl::AddModule(std::vector<llvm::StringRef> &path,
+ Stream &error_stream)
+{
+ // Fail early.
+
+ if (m_compiler_instance->hadModuleLoaderFatalFailure())
+ {
+ error_stream.PutCString("error: Couldn't load a module because the module loader is in a fatal state.\n");
+ return false;
+ }
+
+ if (!m_compiler_instance->getPreprocessor().getHeaderSearchInfo().lookupModule(path[0]))
+ {
+ error_stream.Printf("error: Header search couldn't locate module %s\n", path[0].str().c_str());
+ 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)
+ {
+ clang_path.push_back(std::make_pair(&m_compiler_instance->getASTContext().Idents.get(component),
+ source_manager.getLocForStartOfFile(source_manager.getMainFileID()).getLocWithOffset(source_loc_counter++)));
+ }
+ }
+
+ StoringDiagnosticConsumer *diagnostic_consumer = static_cast<StoringDiagnosticConsumer *>(m_compiler_instance->getDiagnostics().getClient());
+
+ diagnostic_consumer->ClearDiagnostics();
+
+ clang::Module *top_level_module = DoGetModule(clang_path.front(), false);
+
+ 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());
+ return false;
+ }
+
+ clang::Module *submodule = top_level_module;
+
+ for (size_t ci = 1; ci < path.size(); ++ci)
+ {
+ llvm::StringRef &component = path[ci];
+ submodule = submodule->findSubmodule(component.str());
+ if (!submodule)
+ {
+ diagnostic_consumer->DumpDiagnostics(error_stream);
+ error_stream.Printf("error: Couldn't load submodule %s\n", component.str().c_str());
+ return false;
+ }
+ }
+
+ clang::Module *requested_module = DoGetModule(clang_path, true);
+
+ return (requested_module != nullptr);
+}
+
+// ClangImporter::lookupValue
+
+uint32_t
+ClangModulesDeclVendorImpl::FindDecls (const ConstString &name,
+ bool append,
+ uint32_t max_matches,
+ std::vector <clang::NamedDecl*> &decls)
+{
+ if (!append)
+ decls.clear();
+
+ clang::IdentifierInfo &ident = m_compiler_instance->getASTContext().Idents.get(name.GetStringRef());
+
+ clang::LookupResult lookup_result(m_compiler_instance->getSema(),
+ clang::DeclarationName(&ident),
+ clang::SourceLocation(),
+ clang::Sema::LookupOrdinaryName);
+
+ m_compiler_instance->getSema().LookupName(lookup_result, m_compiler_instance->getSema().getScopeForContext(m_compiler_instance->getASTContext().getTranslationUnitDecl()));
+
+ uint32_t num_matches = 0;
+
+ for (clang::NamedDecl *named_decl : lookup_result)
+ {
+ if (num_matches >= max_matches)
+ return num_matches;
+
+ decls.push_back(named_decl);
+ ++num_matches;
+ }
+
+ return num_matches;
+}
+
+ClangModulesDeclVendorImpl::~ClangModulesDeclVendorImpl()
+{
+}
+
+clang::ModuleLoadResult
+ClangModulesDeclVendorImpl::DoGetModule(clang::ModuleIdPath path,
+ bool make_visible)
+{
+ clang::Module::NameVisibilityKind visibility = make_visible ? clang::Module::AllVisible : clang::Module::Hidden;
+
+ const bool is_inclusion_directive = false;
+
+ return m_compiler_instance->loadModule(path.front().second, path, visibility, is_inclusion_directive);
+}
+
+static const char *ModuleImportBufferName = "LLDBModulesMemoryBuffer";
+
+lldb_private::ClangModulesDeclVendor *
+ClangModulesDeclVendor::Create(Target &target)
+{
+ // FIXME we should insure programmatically that the expression parser's compiler and the modules runtime's
+ // compiler are both initialized in the same way – preferably by the same code.
+
+ if (!target.GetPlatform()->SupportsModules())
+ return nullptr;
+
+ const ArchSpec &arch = target.GetArchitecture();
+
+ std::vector<std::string> compiler_invocation_arguments =
+ {
+ "-fmodules",
+ "-fcxx-modules",
+ "-fsyntax-only",
+ "-femit-all-decls",
+ "-target", arch.GetTriple().str(),
+ "-fmodules-validate-system-headers",
+ "-Werror=non-modular-include-in-framework-module"
+ };
+
+ target.GetPlatform()->AddClangModuleCompilationOptions(compiler_invocation_arguments);
+
+ compiler_invocation_arguments.push_back(ModuleImportBufferName);
+
+ // Add additional search paths with { "-I", path } or { "-F", path } here.
+
+ {
+ llvm::SmallString<128> DefaultModuleCache;
+ const bool erased_on_reboot = false;
+ llvm::sys::path::system_temp_directory(erased_on_reboot, DefaultModuleCache);
+ llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang");
+ llvm::sys::path::append(DefaultModuleCache, "ModuleCache");
+ std::string module_cache_argument("-fmodules-cache-path=");
+ module_cache_argument.append(DefaultModuleCache.str().str());
+ compiler_invocation_arguments.push_back(module_cache_argument);
+ }
+
+ {
+ FileSpec clang_resource_dir = GetResourceDir();
+
+ if (clang_resource_dir.IsDirectory())
+ {
+ compiler_invocation_arguments.push_back("-resource-dir");
+ compiler_invocation_arguments.push_back(clang_resource_dir.GetPath());
+ }
+ }
+
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine = clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions,
+ new StoringDiagnosticConsumer);
+
+ std::vector<const char *> compiler_invocation_argument_cstrs;
+
+ for (const std::string &arg : compiler_invocation_arguments) {
+ compiler_invocation_argument_cstrs.push_back(arg.c_str());
+ }
+
+ llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> invocation(clang::createInvocationFromCommandLine(compiler_invocation_argument_cstrs, diagnostics_engine));
+
+ if (!invocation)
+ return nullptr;
+
+ std::unique_ptr<llvm::MemoryBuffer> source_buffer = llvm::MemoryBuffer::getMemBuffer("extern int __lldb __attribute__((unavailable));",
+ ModuleImportBufferName);
+
+ invocation->getPreprocessorOpts().addRemappedFile(ModuleImportBufferName, source_buffer.release());
+
+ std::unique_ptr<clang::CompilerInstance> instance(new clang::CompilerInstance);
+
+ instance->setDiagnostics(diagnostics_engine.get());
+ instance->setInvocation(invocation.get());
+
+ std::unique_ptr<clang::FrontendAction> action(new clang::SyntaxOnlyAction);
+
+ instance->setTarget(clang::TargetInfo::CreateTargetInfo(*diagnostics_engine, instance->getInvocation().TargetOpts));
+
+ if (!instance->hasTarget())
+ return nullptr;
+
+ instance->getTarget().adjust(instance->getLangOpts());
+
+ if (!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0]))
+ return nullptr;
+
+ instance->getPreprocessor().enableIncrementalProcessing();
+
+ instance->createModuleManager();
+
+ instance->createSema(action->getTranslationUnitKind(), nullptr);
+
+ const bool skipFunctionBodies = false;
+ std::unique_ptr<clang::Parser> parser(new clang::Parser(instance->getPreprocessor(), instance->getSema(), skipFunctionBodies));
+
+ instance->getPreprocessor().EnterMainSourceFile();
+ parser->Initialize();
+
+ clang::Parser::DeclGroupPtrTy parsed;
+
+ while (!parser->ParseTopLevelDecl(parsed));
+
+ return new ClangModulesDeclVendorImpl (diagnostics_engine, invocation, std::move(instance), std::move(parser));
+}
diff --git a/source/Expression/ClangUserExpression.cpp b/source/Expression/ClangUserExpression.cpp
index 52ef4d310352..55148462bbc0 100644
--- a/source/Expression/ClangUserExpression.cpp
+++ b/source/Expression/ClangUserExpression.cpp
@@ -619,15 +619,14 @@ GetObjectPointer (lldb::StackFrameSP frame_sp,
valobj_sp = frame_sp->GetValueForVariableExpressionPath(object_name.AsCString(),
lldb::eNoDynamicValues,
- StackFrame::eExpressionPathOptionCheckPtrVsMember ||
- StackFrame::eExpressionPathOptionsAllowDirectIVarAccess ||
- StackFrame::eExpressionPathOptionsNoFragileObjcIvar ||
- StackFrame::eExpressionPathOptionsNoSyntheticChildren ||
+ StackFrame::eExpressionPathOptionCheckPtrVsMember |
+ StackFrame::eExpressionPathOptionsNoFragileObjcIvar |
+ StackFrame::eExpressionPathOptionsNoSyntheticChildren |
StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
var_sp,
err);
- if (!err.Success())
+ if (!err.Success() || !valobj_sp.get())
return LLDB_INVALID_ADDRESS;
lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
@@ -885,17 +884,17 @@ ClangUserExpression::Execute (Stream &error_stream,
args.push_back(struct_address);
- ThreadPlanCallUserExpression *user_expression_plan =
- new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
- wrapper_address,
- args,
- options,
- shared_ptr_to_me);
- lldb::ThreadPlanSP call_plan_sp(user_expression_plan);
+ lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
+ wrapper_address,
+ args,
+ options,
+ shared_ptr_to_me));
if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream))
return lldb::eExpressionSetupError;
+ ThreadPlanCallUserExpression *user_expression_plan = static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get());
+
lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer();
function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize();
@@ -1070,7 +1069,7 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
user_expression_sp,
expr_result);
- if (options.GetResultIsInternal())
+ if (options.GetResultIsInternal() && expr_result && process)
{
process->GetTarget().GetPersistentVariables().RemovePersistentVariable (expr_result);
}
diff --git a/source/Expression/DWARFExpression.cpp b/source/Expression/DWARFExpression.cpp
index 44b64ab1bf29..827bddd8e7bc 100644
--- a/source/Expression/DWARFExpression.cpp
+++ b/source/Expression/DWARFExpression.cpp
@@ -2690,11 +2690,6 @@ DWARFExpression::Evaluate
}
break;
- default:
- if (error_ptr)
- error_ptr->SetErrorStringWithFormat ("unhandled value type for DW_OP_piece(%" PRIu64 ")", piece_byte_size);
- return false;
-
}
// Check if this is the first piece?
@@ -2880,7 +2875,7 @@ DWARFExpression::Evaluate
if (cfa != LLDB_INVALID_ADDRESS)
{
stack.push_back(Scalar(cfa));
- stack.back().SetValueType (Value::eValueTypeHostAddress);
+ stack.back().SetValueType (Value::eValueTypeLoadAddress);
}
else
if (error_ptr)
diff --git a/source/Expression/IRExecutionUnit.cpp b/source/Expression/IRExecutionUnit.cpp
index 090f88fc1bfe..e7cb728778e6 100644
--- a/source/Expression/IRExecutionUnit.cpp
+++ b/source/Expression/IRExecutionUnit.cpp
@@ -13,6 +13,7 @@
#include "llvm/Support/SourceMgr.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"
#include "lldb/Core/Module.h"
@@ -199,6 +200,11 @@ IRExecutionUnit::DisassembleFunction (Stream &stream,
InstructionList &instruction_list = disassembler_sp->GetInstructionList();
const uint32_t max_opcode_byte_size = instruction_list.GetMaxOpcocdeByteSize();
+ const char *disassemble_format = "${addr-file-or-load}: ";
+ if (exe_ctx.HasTargetScope())
+ {
+ disassemble_format = exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat();
+ }
for (size_t instruction_index = 0, num_instructions = instruction_list.GetSize();
instruction_index < num_instructions;
@@ -209,7 +215,10 @@ IRExecutionUnit::DisassembleFunction (Stream &stream,
max_opcode_byte_size,
true,
true,
- &exe_ctx);
+ &exe_ctx,
+ NULL,
+ NULL,
+ disassemble_format);
stream.PutChar('\n');
}
// FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
@@ -300,11 +309,9 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
builder.setEngineKind(llvm::EngineKind::JIT)
.setErrorStr(&error_string)
.setRelocationModel(relocModel)
- .setJITMemoryManager(new MemoryManager(*this))
- .setOptLevel(llvm::CodeGenOpt::Less)
- .setAllocateGVsWithCode(true)
+ .setMCJITMemoryManager(std::unique_ptr<MemoryManager>(new MemoryManager(*this)))
.setCodeModel(codeModel)
- .setUseMCJIT(true);
+ .setOptLevel(llvm::CodeGenOpt::Less);
llvm::StringRef mArch;
llvm::StringRef mCPU;
@@ -425,7 +432,7 @@ IRExecutionUnit::~IRExecutionUnit ()
}
IRExecutionUnit::MemoryManager::MemoryManager (IRExecutionUnit &parent) :
- m_default_mm_ap (llvm::JITMemoryManager::CreateDefaultMemManager()),
+ m_default_mm_ap (new llvm::SectionMemoryManager()),
m_parent (parent)
{
}
@@ -433,60 +440,6 @@ IRExecutionUnit::MemoryManager::MemoryManager (IRExecutionUnit &parent) :
IRExecutionUnit::MemoryManager::~MemoryManager ()
{
}
-void
-IRExecutionUnit::MemoryManager::setMemoryWritable ()
-{
- m_default_mm_ap->setMemoryWritable();
-}
-
-void
-IRExecutionUnit::MemoryManager::setMemoryExecutable ()
-{
- m_default_mm_ap->setMemoryExecutable();
-}
-
-
-uint8_t *
-IRExecutionUnit::MemoryManager::startFunctionBody(const llvm::Function *F,
- uintptr_t &ActualSize)
-{
- return m_default_mm_ap->startFunctionBody(F, ActualSize);
-}
-
-uint8_t *
-IRExecutionUnit::MemoryManager::allocateStub(const llvm::GlobalValue* F,
- unsigned StubSize,
- unsigned Alignment)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
- uint8_t *return_value = m_default_mm_ap->allocateStub(F, StubSize, Alignment);
-
- m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
- lldb::ePermissionsReadable | lldb::ePermissionsWritable,
- GetSectionTypeFromSectionName (llvm::StringRef(), AllocationKind::Stub),
- StubSize,
- Alignment,
- eSectionIDInvalid,
- NULL));
-
- if (log)
- {
- log->Printf("IRExecutionUnit::allocateStub (F=%p, StubSize=%u, Alignment=%u) = %p",
- static_cast<const void*>(F), StubSize, Alignment,
- static_cast<void*>(return_value));
- }
-
- return return_value;
-}
-
-void
-IRExecutionUnit::MemoryManager::endFunctionBody(const llvm::Function *F,
- uint8_t *FunctionStart,
- uint8_t *FunctionEnd)
-{
- m_default_mm_ap->endFunctionBody(F, FunctionStart, FunctionEnd);
-}
lldb::SectionType
IRExecutionUnit::GetSectionTypeFromSectionName (const llvm::StringRef &name, IRExecutionUnit::AllocationKind alloc_kind)
@@ -598,30 +551,6 @@ IRExecutionUnit::GetSectionTypeFromSectionName (const llvm::StringRef &name, IRE
}
uint8_t *
-IRExecutionUnit::MemoryManager::allocateSpace(intptr_t Size, unsigned Alignment)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
- uint8_t *return_value = m_default_mm_ap->allocateSpace(Size, Alignment);
-
- m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
- lldb::ePermissionsReadable | lldb::ePermissionsWritable,
- GetSectionTypeFromSectionName (llvm::StringRef(), AllocationKind::Bytes),
- Size,
- Alignment,
- eSectionIDInvalid,
- NULL));
-
- if (log)
- {
- log->Printf("IRExecutionUnit::allocateSpace(Size=%" PRIu64 ", Alignment=%u) = %p",
- (uint64_t)Size, Alignment, return_value);
- }
-
- return return_value;
-}
-
-uint8_t *
IRExecutionUnit::MemoryManager::allocateCodeSection(uintptr_t Size,
unsigned Alignment,
unsigned SectionID,
@@ -675,37 +604,6 @@ IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size,
return return_value;
}
-uint8_t *
-IRExecutionUnit::MemoryManager::allocateGlobal(uintptr_t Size,
- unsigned Alignment)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
- uint8_t *return_value = m_default_mm_ap->allocateGlobal(Size, Alignment);
-
- m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
- lldb::ePermissionsReadable | lldb::ePermissionsWritable,
- GetSectionTypeFromSectionName (llvm::StringRef(), AllocationKind::Global),
- Size,
- Alignment,
- eSectionIDInvalid,
- NULL));
-
- if (log)
- {
- log->Printf("IRExecutionUnit::allocateGlobal(Size=0x%" PRIx64 ", Alignment=%u) = %p",
- (uint64_t)Size, Alignment, return_value);
- }
-
- return return_value;
-}
-
-void
-IRExecutionUnit::MemoryManager::deallocateFunctionBody(void *Body)
-{
- m_default_mm_ap->deallocateFunctionBody(Body);
-}
-
lldb::addr_t
IRExecutionUnit::GetRemoteAddressForLocal (lldb::addr_t local_address)
{
diff --git a/source/Expression/IRForTarget.cpp b/source/Expression/IRForTarget.cpp
index b91e1b46f88e..8e75c32183ec 100644
--- a/source/Expression/IRForTarget.cpp
+++ b/source/Expression/IRForTarget.cpp
@@ -18,6 +18,7 @@
#include "llvm/IR/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Transforms/IPO.h"
+#include "llvm/IR/Metadata.h"
#include "llvm/IR/ValueSymbolTable.h"
#include "clang/AST/ASTContext.h"
@@ -403,18 +404,17 @@ IRForTarget::DeclForGlobal (const GlobalValue *global_val, Module *module)
node_index < num_nodes;
++node_index)
{
- MDNode *metadata_node = named_metadata->getOperand(node_index);
-
+ llvm::MDNode *metadata_node = dyn_cast<llvm::MDNode>(named_metadata->getOperand(node_index));
if (!metadata_node)
return NULL;
if (metadata_node->getNumOperands() != 2)
continue;
- if (metadata_node->getOperand(0) != global_val)
+ if (mdconst::dyn_extract_or_null<GlobalValue>(metadata_node->getOperand(0)) != global_val)
continue;
- ConstantInt *constant_int = dyn_cast<ConstantInt>(metadata_node->getOperand(1));
+ ConstantInt *constant_int = mdconst::dyn_extract<ConstantInt>(metadata_node->getOperand(1));
if (!constant_int)
return NULL;
@@ -639,11 +639,11 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
reinterpret_cast<uint64_t>(result_decl),
false);
- llvm::Value* values[2];
- values[0] = new_result_global;
- values[1] = new_constant_int;
+ llvm::Metadata *values[2];
+ values[0] = ConstantAsMetadata::get(new_result_global);
+ values[1] = ConstantAsMetadata::get(new_constant_int);
- ArrayRef<Value*> value_ref(values, 2);
+ ArrayRef<Metadata *> value_ref(values, 2);
MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref);
NamedMDNode *named_metadata = m_module->getNamedMetadata("clang.global.decl.ptrs");
@@ -1037,7 +1037,7 @@ static bool IsObjCSelectorRef (Value *value)
{
GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value);
- if (!global_variable || !global_variable->hasName() || !global_variable->getName().startswith("\01L_OBJC_SELECTOR_REFERENCES_"))
+ if (!global_variable || !global_variable->hasName() || !global_variable->getName().startswith("OBJC_SELECTOR_REFERENCES_"))
return false;
return true;
@@ -1056,12 +1056,12 @@ IRForTarget::RewriteObjCSelector (Instruction* selector_load)
// Unpack the message name from the selector. In LLVM IR, an objc_msgSend gets represented as
//
- // %tmp = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_" ; <i8*>
+ // %tmp = load i8** @"OBJC_SELECTOR_REFERENCES_" ; <i8*>
// %call = call i8* (i8*, i8*, ...)* @objc_msgSend(i8* %obj, i8* %tmp, ...) ; <i8*>
//
// where %obj is the object pointer and %tmp is the selector.
//
- // @"\01L_OBJC_SELECTOR_REFERENCES_" is a pointer to a character array called @"\01L_OBJC_llvm_moduleETH_VAR_NAllvm_moduleE_".
+ // @"OBJC_SELECTOR_REFERENCES_" is a pointer to a character array called @"\01L_OBJC_llvm_moduleETH_VAR_NAllvm_moduleE_".
// @"\01L_OBJC_llvm_moduleETH_VAR_NAllvm_moduleE_" contains the string.
// Find the pointer's initializer (a ConstantExpr with opcode GetElementPtr) and get the string from its target
@@ -1215,7 +1215,7 @@ IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc)
if (!alloc_md || !alloc_md->getNumOperands())
return false;
- ConstantInt *constant_int = dyn_cast<ConstantInt>(alloc_md->getOperand(0));
+ ConstantInt *constant_int = mdconst::dyn_extract<ConstantInt>(alloc_md->getOperand(0));
if (!constant_int)
return false;
@@ -1246,11 +1246,11 @@ IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc)
NamedMDNode *named_metadata = m_module->getOrInsertNamedMetadata("clang.global.decl.ptrs");
- llvm::Value* values[2];
- values[0] = persistent_global;
- values[1] = constant_int;
+ llvm::Metadata *values[2];
+ values[0] = ConstantAsMetadata::get(persistent_global);
+ values[1] = ConstantAsMetadata::get(constant_int);
- ArrayRef<llvm::Value*> value_ref(values, 2);
+ ArrayRef<llvm::Metadata *> value_ref(values, 2);
MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref);
named_metadata->addOperand(persistent_global_md);
@@ -2043,8 +2043,12 @@ static bool isGuardVariableRef(Value *V)
GlobalVariable *GV = dyn_cast<GlobalVariable>(Old);
- if (!GV || !GV->hasName() || !GV->getName().startswith("_ZGV"))
+ if (!GV || !GV->hasName() ||
+ (!GV->getName().startswith("_ZGV") && // Itanium ABI guard variable
+ !GV->getName().endswith("@4IA"))) // Microsoft ABI guard variable
+ {
return false;
+ }
return true;
}
@@ -2052,20 +2056,8 @@ static bool isGuardVariableRef(Value *V)
void
IRForTarget::TurnGuardLoadIntoZero(llvm::Instruction* guard_load)
{
- Constant* zero(ConstantInt::get(Type::getInt8Ty(m_module->getContext()), 0, true));
-
- for (llvm::User *u : guard_load->users())
- {
- if (isa<Constant>(u))
- {
- // do nothing for the moment
- }
- else
- {
- u->replaceUsesOfWith(guard_load, zero);
- }
- }
-
+ Constant *zero(Constant::getNullValue(guard_load->getType()));
+ guard_load->replaceAllUsesWith(zero);
guard_load->eraseFromParent();
}
diff --git a/source/Host/common/Editline.cpp b/source/Host/common/Editline.cpp
index 7af9f39a7863..b82fbea90c6c 100644
--- a/source/Host/common/Editline.cpp
+++ b/source/Host/common/Editline.cpp
@@ -7,527 +7,913 @@
//
//===----------------------------------------------------------------------===//
+#include <iomanip>
+#include <iostream>
+#include <limits.h>
#include "lldb/Host/Editline.h"
-
+#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Core/Error.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/StringList.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/Mutex.h"
-#include <limits.h>
-
-using namespace lldb;
using namespace lldb_private;
+using namespace lldb_private::line_editor;
-namespace lldb_private {
- typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP;
-
-
- // EditlineHistory objects are sometimes shared between multiple
- // Editline instances with the same program name. This class allows
- // multiple editline instances to
- //
-
- class EditlineHistory
- {
- private:
- // Use static GetHistory() function to get a EditlineHistorySP to one of these objects
- EditlineHistory(const std::string &prefix, uint32_t size, bool unique_entries) :
- m_history (NULL),
- m_event (),
- m_prefix (prefix),
- m_path ()
+// Editline uses careful cursor management to achieve the illusion of editing a multi-line block of text
+// with a single line editor. Preserving this illusion requires fairly careful management of cursor
+// state. Read and understand the relationship between DisplayInput(), MoveCursor(), SetCurrentLine(),
+// and SaveEditedLine() before making changes.
+
+#define ESCAPE "\x1b"
+#define ANSI_FAINT ESCAPE "[2m"
+#define ANSI_UNFAINT ESCAPE "[22m"
+#define ANSI_CLEAR_BELOW ESCAPE "[J"
+#define ANSI_CLEAR_RIGHT ESCAPE "[K"
+#define ANSI_SET_COLUMN_N ESCAPE "[%dG"
+#define ANSI_UP_N_ROWS ESCAPE "[%dA"
+#define ANSI_DOWN_N_ROWS ESCAPE "[%dB"
+
+#if LLDB_EDITLINE_USE_WCHAR
+
+#define EditLineConstString(str) L##str
+#define EditLineStringFormatSpec "%ls"
+
+#else
+
+#define EditLineConstString(str) str
+#define EditLineStringFormatSpec "%s"
+
+// use #defines so wide version functions and structs will resolve to old versions
+// for case of libedit not built with wide char support
+#define history_w history
+#define history_winit history_init
+#define history_wend history_end
+#define HistoryW History
+#define HistEventW HistEvent
+#define LineInfoW LineInfo
+
+#define el_wgets el_gets
+#define el_wgetc el_getc
+#define el_wpush el_push
+#define el_wparse el_parse
+#define el_wset el_set
+#define el_wget el_get
+#define el_wline el_line
+#define el_winsertstr el_insertstr
+#define el_wdeletestr el_deletestr
+
+#endif // #if LLDB_EDITLINE_USE_WCHAR
+
+bool
+IsOnlySpaces (const EditLineStringType & content)
+{
+ for (wchar_t ch : content)
+ {
+ if (ch != EditLineCharType(' '))
+ return false;
+ }
+ return true;
+}
+
+EditLineStringType
+CombineLines (const std::vector<EditLineStringType> & lines)
+{
+ EditLineStringStreamType combined_stream;
+ for (EditLineStringType line : lines)
+ {
+ combined_stream << line.c_str() << "\n";
+ }
+ return combined_stream.str();
+}
+
+std::vector<EditLineStringType>
+SplitLines (const EditLineStringType & input)
+{
+ std::vector<EditLineStringType> result;
+ size_t start = 0;
+ while (start < input.length())
+ {
+ size_t end = input.find ('\n', start);
+ if (end == std::string::npos)
{
- m_history = ::history_init();
- ::history (m_history, &m_event, H_SETSIZE, size);
- if (unique_entries)
- ::history (m_history, &m_event, H_SETUNIQUE, 1);
+ result.insert (result.end(), input.substr (start));
+ break;
}
+ result.insert (result.end(), input.substr (start, end - start));
+ start = end + 1;
+ }
+ return result;
+}
+
+EditLineStringType
+FixIndentation (const EditLineStringType & line, int indent_correction)
+{
+ if (indent_correction == 0)
+ return line;
+ if (indent_correction < 0)
+ return line.substr (-indent_correction);
+ return EditLineStringType (indent_correction, EditLineCharType(' ')) + line;
+}
+
+int
+GetIndentation (const EditLineStringType & line)
+{
+ int space_count = 0;
+ for (EditLineCharType ch : line)
+ {
+ if (ch != EditLineCharType(' '))
+ break;
+ ++space_count;
+ }
+ return space_count;
+}
+
+bool
+IsInputPending (FILE * file)
+{
+ // FIXME: This will be broken on Windows if we ever re-enable Editline. You can't use select
+ // on something that isn't a socket. This will have to be re-written to not use a FILE*, but
+ // instead use some kind of yet-to-be-created abstraction that select-like functionality on
+ // non-socket objects.
+ const int fd = fileno (file);
+ fd_set fds;
+ FD_ZERO (&fds);
+ FD_SET (fd, &fds);
+ timeval timeout = { 0, 0 };
+ return select (fd + 1, &fds, NULL, NULL, &timeout);
+}
+
+namespace lldb_private
+{
+ namespace line_editor
+ {
+ typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP;
+
+ // EditlineHistory objects are sometimes shared between multiple
+ // Editline instances with the same program name.
- const char *
- GetHistoryFilePath()
+ class EditlineHistory
{
- if (m_path.empty() && m_history && !m_prefix.empty())
+ private:
+ // Use static GetHistory() function to get a EditlineHistorySP to one of these objects
+ EditlineHistory (const std::string &prefix, uint32_t size, bool unique_entries) :
+ m_history (NULL),
+ m_event (),
+ m_prefix (prefix),
+ m_path ()
{
- char history_path[PATH_MAX];
- ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_prefix.c_str());
- m_path = std::move(FileSpec(history_path, true).GetPath());
+ m_history = history_winit();
+ history_w (m_history, &m_event, H_SETSIZE, size);
+ if (unique_entries)
+ history_w (m_history, &m_event, H_SETUNIQUE, 1);
+ }
+
+ const char *
+ GetHistoryFilePath()
+ {
+ if (m_path.empty() && m_history && !m_prefix.empty())
+ {
+ std::string parent_path = FileSpec ("~/.lldb", true).GetPath();
+ char history_path[PATH_MAX];
+ if (FileSystem::MakeDirectory(parent_path.c_str(), lldb::eFilePermissionsDirectoryDefault).Success())
+ {
+ snprintf (history_path, sizeof (history_path), "~/.lldb/%s-history", m_prefix.c_str());
+ }
+ else
+ {
+ snprintf (history_path, sizeof (history_path), "~/%s-widehistory", m_prefix.c_str());
+ }
+ m_path = std::move (FileSpec (history_path, true).GetPath());
+ }
+ if (m_path.empty())
+ return NULL;
+ return m_path.c_str();
}
- if (m_path.empty())
- return NULL;
- return m_path.c_str();
- }
-
- public:
-
- ~EditlineHistory()
- {
- Save ();
- if (m_history)
+ public:
+
+ ~EditlineHistory()
{
- ::history_end (m_history);
- m_history = NULL;
+ Save();
+
+ if (m_history)
+ {
+ history_wend (m_history);
+ m_history = NULL;
+ }
}
- }
-
- static EditlineHistorySP
- GetHistory (const std::string &prefix)
- {
- typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap;
- static Mutex g_mutex(Mutex::eMutexTypeRecursive);
- static WeakHistoryMap g_weak_map;
- Mutex::Locker locker (g_mutex);
- WeakHistoryMap::const_iterator pos = g_weak_map.find (prefix);
- EditlineHistorySP history_sp;
- if (pos != g_weak_map.end())
+
+ static EditlineHistorySP
+ GetHistory (const std::string &prefix)
{
- history_sp = pos->second.lock();
- if (history_sp)
- return history_sp;
- g_weak_map.erase(pos);
+ typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap;
+ static Mutex g_mutex (Mutex::eMutexTypeRecursive);
+ static WeakHistoryMap g_weak_map;
+ Mutex::Locker locker (g_mutex);
+ WeakHistoryMap::const_iterator pos = g_weak_map.find (prefix);
+ EditlineHistorySP history_sp;
+ if (pos != g_weak_map.end())
+ {
+ history_sp = pos->second.lock();
+ if (history_sp)
+ return history_sp;
+ g_weak_map.erase (pos);
+ }
+ history_sp.reset (new EditlineHistory (prefix, 800, true));
+ g_weak_map[prefix] = history_sp;
+ return history_sp;
}
- history_sp.reset(new EditlineHistory(prefix, 800, true));
- g_weak_map[prefix] = history_sp;
- return history_sp;
- }
-
- bool IsValid() const
- {
- return m_history != NULL;
- }
-
- ::History *
- GetHistoryPtr ()
- {
- return m_history;
- }
-
- void
- Enter (const char *line_cstr)
- {
- if (m_history)
- ::history (m_history, &m_event, H_ENTER, line_cstr);
- }
-
- bool
- Load ()
- {
- if (m_history)
+
+ bool IsValid() const
{
- const char *path = GetHistoryFilePath();
- if (path)
+ return m_history != NULL;
+ }
+
+ HistoryW *
+ GetHistoryPtr ()
+ {
+ return m_history;
+ }
+
+ void
+ Enter (const EditLineCharType *line_cstr)
+ {
+ if (m_history)
+ history_w (m_history, &m_event, H_ENTER, line_cstr);
+ }
+
+ bool
+ Load ()
+ {
+ if (m_history)
{
- ::history (m_history, &m_event, H_LOAD, path);
- return true;
+ const char *path = GetHistoryFilePath();
+ if (path)
+ {
+ history_w (m_history, &m_event, H_LOAD, path);
+ return true;
+ }
}
+ return false;
}
- return false;
- }
-
- bool
- Save ()
- {
- if (m_history)
+
+ bool
+ Save ()
{
- const char *path = GetHistoryFilePath();
- if (path)
+ if (m_history)
{
- ::history (m_history, &m_event, H_SAVE, path);
- return true;
+ const char *path = GetHistoryFilePath();
+ if (path)
+ {
+ history_w (m_history, &m_event, H_SAVE, path);
+ return true;
+ }
}
+ return false;
}
- return false;
- }
-
- protected:
- ::History *m_history; // The history object
- ::HistEvent m_event;// The history event needed to contain all history events
- std::string m_prefix; // The prefix name (usually the editline program name) to use when loading/saving history
- std::string m_path; // Path to the history file
- };
+
+ protected:
+ HistoryW * m_history; // The history object
+ HistEventW m_event; // The history event needed to contain all history events
+ std::string m_prefix; // The prefix name (usually the editline program name) to use when loading/saving history
+ std::string m_path; // Path to the history file
+ };
+ }
}
+//------------------------------------------------------------------
+// Editline private methods
+//------------------------------------------------------------------
-static const char k_prompt_escape_char = '\1';
-
-Editline::Editline (const char *prog, // prog can't be NULL
- const char *prompt, // can be NULL for no prompt
- bool configure_for_multiline,
- FILE *fin,
- FILE *fout,
- FILE *ferr) :
- m_editline (NULL),
- m_history_sp (),
- m_prompt (),
- m_lines_prompt (),
- m_getting_char (false),
- m_completion_callback (NULL),
- m_completion_callback_baton (NULL),
- m_line_complete_callback (NULL),
- m_line_complete_callback_baton (NULL),
- m_lines_command (Command::None),
- m_line_offset (0),
- m_lines_curr_line (0),
- m_lines_max_line (0),
- m_file (fileno(fin), false),
- m_prompt_with_line_numbers (false),
- m_getting_line (false),
- m_got_eof (false),
- m_interrupted (false)
-{
- if (prog && prog[0])
- {
- m_editline = ::el_init(prog, fin, fout, ferr);
-
- // Get a shared history instance
- m_history_sp = EditlineHistory::GetHistory(prog);
+void
+Editline::SetBaseLineNumber (int line_number)
+{
+ std::stringstream line_number_stream;
+ line_number_stream << line_number;
+ m_base_line_number = line_number;
+ m_line_number_digits = std::max (3, (int)line_number_stream.str().length() + 1);
+}
+
+std::string
+Editline::PromptForIndex (int line_index)
+{
+ bool use_line_numbers = m_multiline_enabled && m_base_line_number > 0;
+ std::string prompt = m_set_prompt;
+ if (use_line_numbers && prompt.length() == 0)
+ {
+ prompt = ": ";
}
- else
+ std::string continuation_prompt = prompt;
+ if (m_set_continuation_prompt.length() > 0)
{
- m_editline = ::el_init("lldb-tmp", fin, fout, ferr);
+ continuation_prompt = m_set_continuation_prompt;
+
+ // Ensure that both prompts are the same length through space padding
+ while (continuation_prompt.length() < prompt.length())
+ {
+ continuation_prompt += ' ';
+ }
+ while (prompt.length() < continuation_prompt.length())
+ {
+ prompt += ' ';
+ }
}
- if (prompt && prompt[0])
- SetPrompt (prompt);
+ if (use_line_numbers)
+ {
+ StreamString prompt_stream;
+ prompt_stream.Printf("%*d%s", m_line_number_digits, m_base_line_number + line_index,
+ (line_index == 0) ? prompt.c_str() : continuation_prompt.c_str());
+ return std::move (prompt_stream.GetString());
+ }
+ return (line_index == 0) ? prompt : continuation_prompt;
+}
- //::el_set (m_editline, EL_BIND, "^[[A", NULL); // Print binding for up arrow key
- //::el_set (m_editline, EL_BIND, "^[[B", NULL); // Print binding for up down key
+void
+Editline::SetCurrentLine (int line_index)
+{
+ m_current_line_index = line_index;
+ m_current_prompt = PromptForIndex (line_index);
+}
+
+int
+Editline::GetPromptWidth()
+{
+ return (int)PromptForIndex (0).length();
+}
- assert (m_editline);
- ::el_set (m_editline, EL_CLIENTDATA, this);
+bool
+Editline::IsEmacs()
+{
+ const char * editor;
+ el_get (m_editline, EL_EDITOR, &editor);
+ return editor[0] == 'e';
+}
- // only defined for newer versions of editline
-#ifdef EL_PROMPT_ESC
- ::el_set (m_editline, EL_PROMPT_ESC, GetPromptCallback, k_prompt_escape_char);
-#else
- // fall back on old prompt setting code
- ::el_set (m_editline, EL_PROMPT, GetPromptCallback);
-#endif
- ::el_set (m_editline, EL_EDITOR, "emacs");
- if (m_history_sp && m_history_sp->IsValid())
+bool
+Editline::IsOnlySpaces()
+{
+ const LineInfoW * info = el_wline (m_editline);
+ for (const EditLineCharType * character = info->buffer; character < info->lastchar; character++)
{
- ::el_set (m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr());
+ if (*character != ' ')
+ return false;
}
- ::el_set (m_editline, EL_ADDFN, "lldb-complete", "Editline completion function", Editline::CallbackComplete);
- // Keep old "lldb_complete" mapping for older clients that used this in their .editrc. editline also
- // has a bad bug where if you have a bind command that tries to bind to a function name that doesn't
- // exist, it will corrupt the heap and probably crash your process later.
- ::el_set (m_editline, EL_ADDFN, "lldb_complete", "Editline completion function", Editline::CallbackComplete);
- ::el_set (m_editline, EL_ADDFN, "lldb-edit-prev-line", "Editline edit prev line", Editline::CallbackEditPrevLine);
- ::el_set (m_editline, EL_ADDFN, "lldb-edit-next-line", "Editline edit next line", Editline::CallbackEditNextLine);
+ return true;
+}
- ::el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string
- ::el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does.
- ::el_set (m_editline, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key.
- ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be auto complete
-
- if (configure_for_multiline)
+int
+Editline::GetLineIndexForLocation (CursorLocation location, int cursor_row)
+{
+ int line = 0;
+ if (location == CursorLocation::EditingPrompt || location == CursorLocation::BlockEnd ||
+ location == CursorLocation::EditingCursor)
{
- // Use escape sequences for control characters due to bugs in editline
- // where "-k up" and "-k down" don't always work.
- ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow
- ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow
- // Bindings for next/prev history
- ::el_set (m_editline, EL_BIND, "^P", "ed-prev-history", NULL); // Map up arrow
- ::el_set (m_editline, EL_BIND, "^N", "ed-next-history", NULL); // Map down arrow
+ for (unsigned index = 0; index < m_current_line_index; index++)
+ {
+ line += CountRowsForLine (m_input_lines[index]);
+ }
+ if (location == CursorLocation::EditingCursor)
+ {
+ line += cursor_row;
+ }
+ else if (location == CursorLocation::BlockEnd)
+ {
+ for (unsigned index = m_current_line_index; index < m_input_lines.size(); index++)
+ {
+ line += CountRowsForLine (m_input_lines[index]);
+ }
+ --line;
+ }
}
- else
+ return line;
+}
+
+void
+Editline::MoveCursor (CursorLocation from, CursorLocation to)
+{
+ const LineInfoW * info = el_wline (m_editline);
+ int editline_cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth());
+ int editline_cursor_row = editline_cursor_position / m_terminal_width;
+
+ // Determine relative starting and ending lines
+ int fromLine = GetLineIndexForLocation (from, editline_cursor_row);
+ int toLine = GetLineIndexForLocation (to, editline_cursor_row);
+ if (toLine != fromLine)
{
- // Use escape sequences for control characters due to bugs in editline
- // where "-k up" and "-k down" don't always work.
- ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow
- ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow
+ fprintf (m_output_file, (toLine > fromLine) ? ANSI_DOWN_N_ROWS : ANSI_UP_N_ROWS, std::abs (toLine - fromLine));
}
- // Source $PWD/.editrc then $HOME/.editrc
- ::el_source (m_editline, NULL);
-
- // Always read through our callback function so we don't read
- // stuff we aren't supposed to. This also stops the extra echoing
- // that can happen when you have more input than editline can handle
- // at once.
- SetGetCharCallback(GetCharFromInputFileCallback);
-
- LoadHistory();
+ // Determine target column
+ int toColumn = 1;
+ if (to == CursorLocation::EditingCursor)
+ {
+ toColumn = editline_cursor_position - (editline_cursor_row * m_terminal_width) + 1;
+ }
+ else if (to == CursorLocation::BlockEnd)
+ {
+ toColumn = ((m_input_lines[m_input_lines.size() - 1].length() + GetPromptWidth()) % 80) + 1;
+ }
+ fprintf (m_output_file, ANSI_SET_COLUMN_N, toColumn);
}
-Editline::~Editline()
+void
+Editline::DisplayInput (int firstIndex)
{
- // EditlineHistory objects are sometimes shared between multiple
- // Editline instances with the same program name. So just release
- // our shared pointer and if we are the last owner, it will save the
- // history to the history save file automatically.
- m_history_sp.reset();
+ fprintf (m_output_file, ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW, 1);
+ int line_count = (int)m_input_lines.size();
+ const char *faint = m_color_prompts ? ANSI_FAINT : "";
+ const char *unfaint = m_color_prompts ? ANSI_UNFAINT : "";
- // Disable edit mode to stop the terminal from flushing all input
- // during the call to el_end() since we expect to have multiple editline
- // instances in this program.
- ::el_set (m_editline, EL_EDITMODE, 0);
+ for (int index = firstIndex; index < line_count; index++)
+ {
+ fprintf (m_output_file, "%s" "%s" "%s" EditLineStringFormatSpec " ",
+ faint,
+ PromptForIndex (index).c_str(),
+ unfaint,
+ m_input_lines[index].c_str());
+ if (index < line_count - 1)
+ fprintf (m_output_file, "\n");
+ }
+}
- ::el_end(m_editline);
- m_editline = NULL;
+
+int
+Editline::CountRowsForLine (const EditLineStringType & content)
+{
+ auto prompt = PromptForIndex (0); // Prompt width is constant during an edit session
+ int line_length = (int)(content.length() + prompt.length());
+ return (line_length / m_terminal_width) + 1;
}
void
-Editline::SetGetCharCallback (GetCharCallbackType callback)
+Editline::SaveEditedLine()
{
- ::el_set (m_editline, EL_GETCFN, callback);
+ const LineInfoW * info = el_wline (m_editline);
+ m_input_lines[m_current_line_index] = EditLineStringType (info->buffer, info->lastchar - info->buffer);
}
-bool
-Editline::LoadHistory ()
+StringList
+Editline::GetInputAsStringList(int line_count)
{
- if (m_history_sp)
- return m_history_sp->Load();
- return false;
+ StringList lines;
+ for (EditLineStringType line : m_input_lines)
+ {
+ if (line_count == 0)
+ break;
+#if LLDB_EDITLINE_USE_WCHAR
+ lines.AppendString (m_utf8conv.to_bytes (line));
+#else
+ lines.AppendString(line);
+#endif
+ --line_count;
+ }
+ return lines;
}
-bool
-Editline::SaveHistory ()
+unsigned char
+Editline::RecallHistory (bool earlier)
{
- if (m_history_sp)
- return m_history_sp->Save();
- return false;
-}
+ if (!m_history_sp || !m_history_sp->IsValid())
+ return CC_ERROR;
+
+ HistoryW * pHistory = m_history_sp->GetHistoryPtr();
+ HistEventW history_event;
+ std::vector<EditLineStringType> new_input_lines;
+
+ // Treat moving from the "live" entry differently
+ if (!m_in_history)
+ {
+ if (earlier == false)
+ return CC_ERROR; // Can't go newer than the "live" entry
+ if (history_w (pHistory, &history_event, H_FIRST) == -1)
+ return CC_ERROR;
+
+ // Save any edits to the "live" entry in case we return by moving forward in history
+ // (it would be more bash-like to save over any current entry, but libedit doesn't
+ // offer the ability to add entries anywhere except the end.)
+ SaveEditedLine();
+ m_live_history_lines = m_input_lines;
+ m_in_history = true;
+ }
+ else
+ {
+ if (history_w (pHistory, &history_event, earlier ? H_NEXT : H_PREV) == -1)
+ {
+ // Can't move earlier than the earliest entry
+ if (earlier)
+ return CC_ERROR;
+ // ... but moving to newer than the newest yields the "live" entry
+ new_input_lines = m_live_history_lines;
+ m_in_history = false;
+ }
+ }
+
+ // If we're pulling the lines from history, split them apart
+ if (m_in_history)
+ new_input_lines = SplitLines (history_event.str);
-Error
-Editline::PrivateGetLine(std::string &line)
+ // Erase the current edit session and replace it with a new one
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ m_input_lines = new_input_lines;
+ DisplayInput();
+
+ // Prepare to edit the last line when moving to previous entry, or the first line
+ // when moving to next entry
+ SetCurrentLine (m_current_line_index = earlier ? (int)m_input_lines.size() - 1 : 0);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ return CC_NEWLINE;
+}
+
+int
+Editline::GetCharacter (EditLineCharType * c)
{
- Error error;
- if (m_interrupted)
+ const LineInfoW * info = el_wline (m_editline);
+
+ // Paint a faint version of the desired prompt over the version libedit draws
+ // (will only be requested if colors are supported)
+ if (m_needs_prompt_repaint)
{
- error.SetErrorString("interrupted");
- return error;
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+ fprintf (m_output_file, "%s" "%s" "%s", ANSI_FAINT, Prompt(), ANSI_UNFAINT);
+ MoveCursor (CursorLocation::EditingPrompt, CursorLocation::EditingCursor);
+ m_needs_prompt_repaint = false;
}
- line.clear();
- if (m_editline != NULL)
+ if (m_multiline_enabled)
{
- int line_len = 0;
- // Call el_gets to prompt the user and read the user's input.
- const char *line_cstr = ::el_gets (m_editline, &line_len);
-
- static int save_errno = (line_len < 0) ? errno : 0;
-
- if (save_errno != 0)
+ // Detect when the number of rows used for this input line changes due to an edit
+ int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth());
+ int new_line_rows = (lineLength / m_terminal_width) + 1;
+ if (m_current_line_rows != -1 && new_line_rows != m_current_line_rows)
{
- error.SetError(save_errno, eErrorTypePOSIX);
+ // Respond by repainting the current state from this line on
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+ SaveEditedLine();
+ DisplayInput (m_current_line_index);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingCursor);
}
- else if (line_cstr)
+ m_current_line_rows = new_line_rows;
+ }
+
+ // Read an actual character
+ while (true)
+ {
+ lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
+ char ch = 0;
+ m_editor_getting_char = true;
+ int read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
+ m_editor_getting_char = false;
+ if (read_count)
{
- // Decrement the length so we don't have newline characters in "line" for when
- // we assign the cstr into the std::string
- llvm::StringRef line_ref (line_cstr);
- line_ref = line_ref.rtrim("\n\r");
-
- if (!line_ref.empty() && !m_interrupted)
+#if LLDB_EDITLINE_USE_WCHAR
+ // After the initial interruptible read, this is guaranteed not to block
+ ungetc (ch, m_input_file);
+ *c = fgetwc (m_input_file);
+ if (*c != WEOF)
+ return 1;
+#else
+ *c = ch;
+ if(*c != EOF)
+ return 1;
+#endif
+ }
+ else
+ {
+ switch (status)
{
- // We didn't strip the newlines, we just adjusted the length, and
- // we want to add the history item with the newlines
- if (m_history_sp)
- m_history_sp->Enter(line_cstr);
-
- // Copy the part of the c string that we want (removing the newline chars)
- line = std::move(line_ref.str());
+ case lldb::eConnectionStatusInterrupted:
+ m_editor_status = EditorStatus::Interrupted;
+ printf ("^C\n");
+ return 0;
+
+ case lldb::eConnectionStatusSuccess: // Success
+ break;
+
+ case lldb::eConnectionStatusError: // Check GetError() for details
+ case lldb::eConnectionStatusTimedOut: // Request timed out
+ case lldb::eConnectionStatusEndOfFile: // End-of-file encountered
+ case lldb::eConnectionStatusNoConnection: // No connection
+ case lldb::eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
+ m_editor_status = EditorStatus::EndOfInput;
+ return 0;
}
}
}
- else
- {
- error.SetErrorString("the EditLine instance has been deleted");
- }
- return error;
}
+const char *
+Editline::Prompt()
+{
+ if (m_color_prompts)
+ m_needs_prompt_repaint = true;
+ return m_current_prompt.c_str();
+}
-Error
-Editline::GetLine(std::string &line, bool &interrupted)
+unsigned char
+Editline::BreakLineCommand (int ch)
{
- Error error;
- interrupted = false;
- line.clear();
+ // Preserve any content beyond the cursor, truncate and save the current line
+ const LineInfoW * info = el_wline (m_editline);
+ auto current_line = EditLineStringType (info->buffer, info->cursor - info->buffer);
+ auto new_line_fragment = EditLineStringType (info->cursor, info->lastchar - info->cursor);
+ m_input_lines[m_current_line_index] = current_line;
+
+ // Ignore whitespace-only extra fragments when breaking a line
+ if (::IsOnlySpaces (new_line_fragment))
+ new_line_fragment = EditLineConstString("");
- // Set arrow key bindings for up and down arrows for single line
- // mode where up and down arrows do prev/next history
- m_interrupted = false;
+ // Establish the new cursor position at the start of a line when inserting a line break
+ m_revert_cursor_index = 0;
- if (!m_got_eof)
+ // Don't perform end of input detection or automatic formatting when pasting
+ if (!IsInputPending (m_input_file))
{
- if (m_getting_line)
+ // If this is the end of the last line, treat this as a potential exit
+ if (m_current_line_index == m_input_lines.size() - 1 && new_line_fragment.length() == 0)
{
- error.SetErrorString("already getting a line");
- return error;
+ bool end_of_input = true;
+ if (m_is_input_complete_callback)
+ {
+ SaveEditedLine();
+ auto lines = GetInputAsStringList();
+ end_of_input = m_is_input_complete_callback (this, lines, m_is_input_complete_callback_baton);
+
+ // The completion test is allowed to change the input lines when complete
+ if (end_of_input)
+ {
+ m_input_lines.clear();
+ for (unsigned index = 0; index < lines.GetSize(); index++)
+ {
+#if LLDB_EDITLINE_USE_WCHAR
+ m_input_lines.insert (m_input_lines.end(), m_utf8conv.from_bytes (lines[index]));
+#else
+ m_input_lines.insert (m_input_lines.end(), lines[index]);
+#endif
+ }
+ }
+ }
+ if (end_of_input)
+ {
+ fprintf (m_output_file, "\n");
+ m_editor_status = EditorStatus::Complete;
+ return CC_NEWLINE;
+ }
}
- if (m_lines_curr_line > 0)
+
+ // Apply smart indentation
+ if (m_fix_indentation_callback)
{
- error.SetErrorString("already getting lines");
- return error;
+ StringList lines = GetInputAsStringList (m_current_line_index + 1);
+#if LLDB_EDITLINE_USE_WCHAR
+ lines.AppendString (m_utf8conv.to_bytes (new_line_fragment));
+#else
+ lines.AppendString (new_line_fragment);
+#endif
+
+ int indent_correction = m_fix_indentation_callback (this, lines, 0, m_fix_indentation_callback_baton);
+ new_line_fragment = FixIndentation(new_line_fragment, indent_correction);
+ m_revert_cursor_index = GetIndentation(new_line_fragment);
}
- m_getting_line = true;
- error = PrivateGetLine(line);
- m_getting_line = false;
}
+
+ // Insert the new line and repaint everything from the split line on down
+ m_input_lines.insert (m_input_lines.begin() + m_current_line_index + 1, new_line_fragment);
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+ DisplayInput (m_current_line_index);
+
+ // Reposition the cursor to the right line and prepare to edit the new line
+ SetCurrentLine (m_current_line_index + 1);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ return CC_NEWLINE;
+}
- interrupted = m_interrupted;
-
- if (m_got_eof && line.empty())
+unsigned char
+Editline::DeleteNextCharCommand (int ch)
+{
+ LineInfoW * info = (LineInfoW *)el_wline (m_editline);
+
+ // Just delete the next character normally if possible
+ if (info->cursor < info->lastchar)
{
- // Only set the error if we didn't get an error back from PrivateGetLine()
- if (error.Success())
- error.SetErrorString("end of file");
+ info->cursor++;
+ el_deletestr (m_editline, 1);
+ return CC_REFRESH;
}
- return error;
+ // Fail when at the end of the last line, except when ^D is pressed on
+ // the line is empty, in which case it is treated as EOF
+ if (m_current_line_index == m_input_lines.size() - 1)
+ {
+ if (ch == 4 && info->buffer == info->lastchar)
+ {
+ fprintf (m_output_file, "^D\n");
+ m_editor_status = EditorStatus::EndOfInput;
+ return CC_EOF;
+ }
+ return CC_ERROR;
+ }
+
+ // Prepare to combine this line with the one below
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+
+ // Insert the next line of text at the cursor and restore the cursor position
+ const EditLineCharType * cursor = info->cursor;
+ el_winsertstr (m_editline, m_input_lines[m_current_line_index + 1].c_str());
+ info->cursor = cursor;
+ SaveEditedLine();
+
+ // Delete the extra line
+ m_input_lines.erase (m_input_lines.begin() + m_current_line_index + 1);
+
+ // Clear and repaint from this line on down
+ DisplayInput (m_current_line_index);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ return CC_REFRESH;
}
-size_t
-Editline::Push (const char *bytes, size_t len)
+unsigned char
+Editline::DeletePreviousCharCommand (int ch)
{
- if (m_editline)
+ LineInfoW * info = (LineInfoW *)el_wline (m_editline);
+
+ // Just delete the previous character normally when not at the start of a line
+ if (info->cursor > info->buffer)
{
- // Must NULL terminate the string for el_push() so we stick it
- // into a std::string first
- ::el_push(m_editline,
- const_cast<char*>(std::string (bytes, len).c_str()));
- return len;
+ el_deletestr (m_editline, 1);
+ return CC_REFRESH;
}
- return 0;
+
+ // No prior line and no prior character? Let the user know
+ if (m_current_line_index == 0)
+ return CC_ERROR;
+
+ // No prior character, but prior line? Combine with the line above
+ SaveEditedLine();
+ SetCurrentLine (m_current_line_index - 1);
+ auto priorLine = m_input_lines[m_current_line_index];
+ m_input_lines.erase (m_input_lines.begin() + m_current_line_index);
+ m_input_lines[m_current_line_index] = priorLine + m_input_lines[m_current_line_index];
+
+ // Repaint from the new line down
+ fprintf (m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, CountRowsForLine (priorLine), 1);
+ DisplayInput (m_current_line_index);
+
+ // Put the cursor back where libedit expects it to be before returning to editing
+ // by telling libedit about the newly inserted text
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ el_winsertstr (m_editline, priorLine.c_str());
+ return CC_REDISPLAY;
}
-
-Error
-Editline::GetLines(const std::string &end_line, StringList &lines, bool &interrupted)
+unsigned char
+Editline::PreviousLineCommand (int ch)
{
- Error error;
- interrupted = false;
- if (m_getting_line)
- {
- error.SetErrorString("already getting a line");
- return error;
+ SaveEditedLine();
+
+ if (m_current_line_index == 0) {
+ return RecallHistory (true);
}
- if (m_lines_curr_line > 0)
+
+ // Start from a known location
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+
+ // Treat moving up from a blank last line as a deletion of that line
+ if (m_current_line_index == m_input_lines.size() - 1 && IsOnlySpaces())
{
- error.SetErrorString("already getting lines");
- return error;
+ m_input_lines.erase (m_input_lines.begin() + m_current_line_index);
+ fprintf (m_output_file, ANSI_CLEAR_BELOW);
}
- // Set arrow key bindings for up and down arrows for multiple line
- // mode where up and down arrows do edit prev/next line
- m_interrupted = false;
-
- LineStatus line_status = LineStatus::Success;
+ SetCurrentLine (m_current_line_index - 1);
+ fprintf (m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N,
+ CountRowsForLine (m_input_lines[m_current_line_index]), 1);
+ return CC_NEWLINE;
+}
- lines.Clear();
+unsigned char
+Editline::NextLineCommand (int ch)
+{
+ SaveEditedLine();
- FILE *out_file = GetOutputFile();
- FILE *err_file = GetErrorFile();
- m_lines_curr_line = 1;
- while (line_status != LineStatus::Done)
+ // Handle attempts to move down from the last line
+ if (m_current_line_index == m_input_lines.size() - 1)
{
- const uint32_t line_idx = m_lines_curr_line-1;
- if (line_idx >= lines.GetSize())
- lines.SetSize(m_lines_curr_line);
- m_lines_max_line = lines.GetSize();
- m_lines_command = Command::None;
- assert(line_idx < m_lines_max_line);
- std::string &line = lines[line_idx];
- error = PrivateGetLine(line);
- if (error.Fail())
+ // Don't add an extra line if the existing last line is blank, move through history instead
+ if (IsOnlySpaces())
{
- line_status = LineStatus::Error;
+ return RecallHistory (false);
}
- else if (m_interrupted)
+
+ // Determine indentation for the new line
+ int indentation = 0;
+ if (m_fix_indentation_callback)
{
- interrupted = true;
- line_status = LineStatus::Done;
+ StringList lines = GetInputAsStringList();
+ lines.AppendString("");
+ indentation = m_fix_indentation_callback (this, lines, 0, m_fix_indentation_callback_baton);
}
- else
- {
- switch (m_lines_command)
- {
- case Command::None:
- if (m_line_complete_callback)
- {
- line_status = m_line_complete_callback (this,
- lines,
- line_idx,
- error,
- m_line_complete_callback_baton);
- }
- else if (line == end_line)
- {
- line_status = LineStatus::Done;
- }
+ m_input_lines.insert (m_input_lines.end(), EditLineStringType (indentation, EditLineCharType(' ')));
+ }
+
+ // Move down past the current line using newlines to force scrolling if needed
+ SetCurrentLine (m_current_line_index + 1);
+ const LineInfoW * info = el_wline (m_editline);
+ int cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth());
+ int cursor_row = cursor_position / m_terminal_width;
+ for (int line_count = 0; line_count < m_current_line_rows - cursor_row; line_count++)
+ {
+ fprintf (m_output_file, "\n");
+ }
+ return CC_NEWLINE;
+}
- if (line_status == LineStatus::Success)
- {
- ++m_lines_curr_line;
- // If we already have content for the next line because
- // we were editing previous lines, then populate the line
- // with the appropriate contents
- if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty())
- ::el_push (m_editline,
- const_cast<char*>(lines[line_idx+1].c_str()));
- }
- else if (line_status == LineStatus::Error)
- {
- // Clear to end of line ("ESC[K"), then print the error,
- // then go to the next line ("\n") and then move cursor up
- // two lines ("ESC[2A").
- fprintf (err_file, "\033[Kerror: %s\n\033[2A", error.AsCString());
- }
- break;
- case Command::EditPrevLine:
- if (m_lines_curr_line > 1)
- {
- //::fprintf (out_file, "\033[1A\033[%uD\033[2K", (uint32_t)(m_lines_prompt.size() + lines[line_idx].size())); // Make cursor go up a line and clear that line
- ::fprintf (out_file, "\033[1A\033[1000D\033[2K");
- if (!lines[line_idx-1].empty())
- ::el_push (m_editline,
- const_cast<char*>(lines[line_idx-1].c_str()));
- --m_lines_curr_line;
- }
- break;
- case Command::EditNextLine:
- // Allow the down arrow to create a new line
- ++m_lines_curr_line;
- //::fprintf (out_file, "\033[1B\033[%uD\033[2K", (uint32_t)(m_lines_prompt.size() + lines[line_idx].size()));
- ::fprintf (out_file, "\033[1B\033[1000D\033[2K");
- if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty())
- ::el_push (m_editline,
- const_cast<char*>(lines[line_idx+1].c_str()));
- break;
- }
+unsigned char
+Editline::FixIndentationCommand (int ch)
+{
+ if (!m_fix_indentation_callback)
+ return CC_NORM;
+
+ // Insert the character by hand prior to correction
+ EditLineCharType inserted[] = { (EditLineCharType)ch, 0 };
+ el_winsertstr (m_editline, inserted);
+ SaveEditedLine();
+ StringList lines = GetInputAsStringList (m_current_line_index + 1);
+
+ // Determine the cursor position
+ LineInfoW * info = (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);
+
+ // Adjust the input buffer to correct indentation
+ if (indent_correction > 0)
+ {
+ info->cursor = info->buffer;
+ el_winsertstr (m_editline, EditLineStringType (indent_correction, EditLineCharType(' ')).c_str());
+ }
+ else if (indent_correction < 0)
+ {
+ info->cursor = info->buffer - indent_correction;
+ el_wdeletestr (m_editline, -indent_correction);
+ }
+ info->cursor = info->buffer + cursor_position + indent_correction;
+ return CC_REFRESH;
+}
+
+unsigned char
+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);
+ info->cursor = info->buffer + m_revert_cursor_index;
+ if (info->cursor > info->lastchar)
+ {
+ info->cursor = info->lastchar;
}
+ m_revert_cursor_index = -1;
}
- m_lines_curr_line = 0;
- m_lines_command = Command::None;
+ return CC_REFRESH;
+}
- // If we have a callback, call it one more time to let the
- // user know the lines are complete
- if (m_line_complete_callback && !interrupted)
- m_line_complete_callback (this,
- lines,
- UINT32_MAX,
- error,
- m_line_complete_callback_baton);
+unsigned char
+Editline::BufferStartCommand (int ch)
+{
+ SaveEditedLine();
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ SetCurrentLine (0);
+ m_revert_cursor_index = 0;
+ return CC_NEWLINE;
+}
- return error;
+unsigned char
+Editline::BufferEndCommand (int ch)
+{
+ SaveEditedLine();
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockEnd);
+ SetCurrentLine ((int)m_input_lines.size() - 1);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ return CC_NEWLINE;
}
unsigned char
-Editline::HandleCompletion (int ch)
+Editline::TabCommand (int ch)
{
- if (m_completion_callback == NULL)
+ if (m_completion_callback == nullptr)
return CC_ERROR;
-
- const LineInfo *line_info = ::el_line(m_editline);
+
+ const LineInfo *line_info = el_line (m_editline);
StringList completions;
int page_size = 40;
-
+
const int num_completions = m_completion_callback (line_info->buffer,
line_info->cursor,
line_info->lastchar,
@@ -536,25 +922,25 @@ Editline::HandleCompletion (int ch)
completions,
m_completion_callback_baton);
- FILE *out_file = GetOutputFile();
-
-// if (num_completions == -1)
-// {
-// ::el_insertstr (m_editline, m_completion_key);
-// return CC_REDISPLAY;
-// }
-// else
+ if (num_completions == 0)
+ return CC_ERROR;
+ // if (num_completions == -1)
+ // {
+ // el_insertstr (m_editline, m_completion_key);
+ // return CC_REDISPLAY;
+ // }
+ // else
if (num_completions == -2)
{
// Replace the entire line with the first string...
- ::el_deletestr (m_editline, line_info->cursor - line_info->buffer);
- ::el_insertstr (m_editline, completions.GetStringAtIndex(0));
+ el_deletestr (m_editline, line_info->cursor - line_info->buffer);
+ el_insertstr (m_editline, completions.GetStringAtIndex (0));
return CC_REDISPLAY;
}
// If we get a longer match display that first.
- const char *completion_str = completions.GetStringAtIndex(0);
- if (completion_str != NULL && *completion_str != '\0')
+ const char *completion_str = completions.GetStringAtIndex (0);
+ if (completion_str != nullptr && *completion_str != '\0')
{
el_insertstr (m_editline, completion_str);
return CC_REDISPLAY;
@@ -563,15 +949,15 @@ Editline::HandleCompletion (int ch)
if (num_completions > 1)
{
int num_elements = num_completions + 1;
- ::fprintf (out_file, "\nAvailable completions:");
+ fprintf (m_output_file, "\n" ANSI_CLEAR_BELOW "Available completions:");
if (num_completions < page_size)
{
for (int i = 1; i < num_elements; i++)
{
- completion_str = completions.GetStringAtIndex(i);
- ::fprintf (out_file, "\n\t%s", completion_str);
+ completion_str = completions.GetStringAtIndex (i);
+ fprintf (m_output_file, "\n\t%s", completion_str);
}
- ::fprintf (out_file, "\n");
+ fprintf (m_output_file, "\n");
}
else
{
@@ -585,17 +971,17 @@ Editline::HandleCompletion (int ch)
endpoint = num_elements;
for (; cur_pos < endpoint; cur_pos++)
{
- completion_str = completions.GetStringAtIndex(cur_pos);
- ::fprintf (out_file, "\n\t%s", completion_str);
+ completion_str = completions.GetStringAtIndex (cur_pos);
+ fprintf (m_output_file, "\n\t%s", completion_str);
}
if (cur_pos >= num_elements)
{
- ::fprintf (out_file, "\n");
+ fprintf (m_output_file, "\n");
break;
}
- ::fprintf (out_file, "\nMore (Y/n/a): ");
+ fprintf (m_output_file, "\nMore (Y/n/a): ");
reply = 'n';
got_char = el_getc(m_editline, &reply);
if (got_char == -1 || reply == 'n')
@@ -604,247 +990,388 @@ Editline::HandleCompletion (int ch)
page_size = num_elements - cur_pos;
}
}
-
+ DisplayInput();
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
}
-
- if (num_completions == 0)
- return CC_REFRESH_BEEP;
- else
- return CC_REDISPLAY;
+ return CC_REDISPLAY;
}
-Editline *
-Editline::GetClientData (::EditLine *e)
+void
+Editline::ConfigureEditor (bool multiline)
{
- Editline *editline = NULL;
- if (e && ::el_get(e, EL_CLIENTDATA, &editline) == 0)
- return editline;
- return NULL;
-}
+ if (m_editline && m_multiline_enabled == multiline)
+ return;
+ m_multiline_enabled = multiline;
+
+ if (m_editline)
+ {
+ // Disable edit mode to stop the terminal from flushing all input
+ // during the call to el_end() since we expect to have multiple editline
+ // instances in this program.
+ el_set (m_editline, EL_EDITMODE, 0);
+ el_end (m_editline);
+ }
+
+ m_editline = el_init (m_editor_name.c_str(), m_input_file, m_output_file, m_error_file);
+ TerminalSizeChanged();
+
+ if (m_history_sp && m_history_sp->IsValid())
+ {
+ m_history_sp->Load();
+ el_wset (m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr());
+ }
+ el_set (m_editline, EL_CLIENTDATA, this);
+ el_set (m_editline, EL_SIGNAL, 0);
+ el_set (m_editline, EL_EDITOR, "emacs");
+ el_set (m_editline, EL_PROMPT, (EditlinePromptCallbackType)([] (EditLine *editline) {
+ return Editline::InstanceFor (editline)->Prompt();
+ }));
-FILE *
-Editline::GetInputFile ()
-{
- return GetFilePointer (m_editline, 0);
+ el_wset (m_editline, EL_GETCFN,
+ (EditlineGetCharCallbackType)([] (EditLine * editline, EditLineCharType * c) {
+ return Editline::InstanceFor (editline)->GetCharacter (c);
+ }));
+
+ // Commands used for multiline support, registered whether or not they're used
+ el_set (m_editline, EL_ADDFN, "lldb-break-line", "Insert a line break",
+ (EditlineCommandCallbackType)([] (EditLine * editline, int ch) {
+ return Editline::InstanceFor (editline)->BreakLineCommand (ch);
+ }));
+ el_set (m_editline, EL_ADDFN, "lldb-delete-next-char", "Delete next character",
+ (EditlineCommandCallbackType)([] (EditLine * editline, int ch) {
+ return Editline::InstanceFor (editline)->DeleteNextCharCommand (ch);
+ }));
+ el_set (m_editline, EL_ADDFN, "lldb-delete-previous-char", "Delete previous character",
+ (EditlineCommandCallbackType)([] (EditLine * editline, int ch) {
+ return Editline::InstanceFor (editline)->DeletePreviousCharCommand (ch);
+ }));
+ el_set (m_editline, EL_ADDFN, "lldb-previous-line", "Move to previous line",
+ (EditlineCommandCallbackType)([] (EditLine * editline, int ch) {
+ return Editline::InstanceFor (editline)->PreviousLineCommand (ch);
+ }));
+ el_set (m_editline, EL_ADDFN, "lldb-next-line", "Move to next line",
+ (EditlineCommandCallbackType)([] (EditLine * editline, int ch) {
+ return Editline::InstanceFor (editline)->NextLineCommand (ch);
+ }));
+ el_set (m_editline, EL_ADDFN, "lldb-buffer-start", "Move to start of buffer",
+ (EditlineCommandCallbackType)([] (EditLine * editline, int ch) {
+ return Editline::InstanceFor (editline)->BufferStartCommand (ch);
+ }));
+ el_set (m_editline, EL_ADDFN, "lldb-buffer-end", "Move to end of buffer",
+ (EditlineCommandCallbackType)([] (EditLine * editline, int ch) {
+ return Editline::InstanceFor (editline)->BufferEndCommand (ch);
+ }));
+ el_set (m_editline, EL_ADDFN, "lldb-fix-indentation", "Fix line indentation",
+ (EditlineCommandCallbackType)([] (EditLine * editline, int ch) {
+ return Editline::InstanceFor (editline)->FixIndentationCommand (ch);
+ }));
+
+ // Register the complete callback under two names for compatibility with older clients using
+ // custom .editrc files (largely becuase libedit has a bad bug where if you have a bind command
+ // that tries to bind to a function name that doesn't exist, it can corrupt the heap and
+ // crash your process later.)
+ EditlineCommandCallbackType complete_callback = [] (EditLine * editline, int ch) {
+ return Editline::InstanceFor (editline)->TabCommand (ch);
+ };
+ el_set (m_editline, EL_ADDFN, "lldb-complete", "Invoke completion", complete_callback);
+ el_set (m_editline, EL_ADDFN, "lldb_complete", "Invoke completion", complete_callback);
+
+ // General bindings we don't mind being overridden
+ if (!multiline) {
+ el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string
+ }
+ el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash in emacs mode
+ el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to auto complete
+
+ // Allow user-specific customization prior to registering bindings we absolutely require
+ el_source (m_editline, NULL);
+
+ // Register an internal binding that external developers shouldn't use
+ el_set (m_editline, EL_ADDFN, "lldb-revert-line", "Revert line to saved state",
+ (EditlineCommandCallbackType)([] (EditLine * editline, int ch) {
+ return Editline::InstanceFor (editline)->RevertLineCommand (ch);
+ }));
+
+ // Register keys that perform auto-indent correction
+ if (m_fix_indentation_callback && m_fix_indentation_callback_chars)
+ {
+ char bind_key[2] = { 0, 0 };
+ const char * indent_chars = m_fix_indentation_callback_chars;
+ while (*indent_chars)
+ {
+ bind_key[0] = *indent_chars;
+ el_set (m_editline, EL_BIND, bind_key, "lldb-fix-indentation", NULL);
+ ++indent_chars;
+ }
+ }
+
+ // Multi-line editor bindings
+ if (multiline)
+ {
+ el_set (m_editline, EL_BIND, "\n", "lldb-break-line", NULL);
+ el_set (m_editline, EL_BIND, "\r", "lldb-break-line", NULL);
+ el_set (m_editline, EL_BIND, "^p", "lldb-previous-line", NULL);
+ el_set (m_editline, EL_BIND, "^n", "lldb-next-line", NULL);
+ el_set (m_editline, EL_BIND, "^?", "lldb-delete-previous-char", NULL);
+ el_set (m_editline, EL_BIND, "^d", "lldb-delete-next-char", NULL);
+ el_set (m_editline, EL_BIND, ESCAPE "[3~", "lldb-delete-next-char", NULL);
+ el_set (m_editline, EL_BIND, ESCAPE "[\\^", "lldb-revert-line", NULL);
+
+ // Editor-specific bindings
+ if (IsEmacs())
+ {
+ el_set (m_editline, EL_BIND, ESCAPE "<", "lldb-buffer-start", NULL);
+ el_set (m_editline, EL_BIND, ESCAPE ">", "lldb-buffer-end", NULL);
+ el_set (m_editline, EL_BIND, ESCAPE "[A", "lldb-previous-line", NULL);
+ el_set (m_editline, EL_BIND, ESCAPE "[B", "lldb-next-line", NULL);
+ }
+ else
+ {
+ el_set (m_editline, EL_BIND, "^H", "lldb-delete-previous-char", NULL);
+
+ el_set (m_editline, EL_BIND, "-a", ESCAPE "[A", "lldb-previous-line", NULL);
+ el_set (m_editline, EL_BIND, "-a", ESCAPE "[B", "lldb-next-line", NULL);
+ el_set (m_editline, EL_BIND, "-a", "x", "lldb-delete-next-char", NULL);
+ el_set (m_editline, EL_BIND, "-a", "^H", "lldb-delete-previous-char", NULL);
+ el_set (m_editline, EL_BIND, "-a", "^?", "lldb-delete-previous-char", NULL);
+
+ // Escape is absorbed exiting edit mode, so re-register important sequences
+ // without the prefix
+ el_set (m_editline, EL_BIND, "-a", "[A", "lldb-previous-line", NULL);
+ el_set (m_editline, EL_BIND, "-a", "[B", "lldb-next-line", NULL);
+ el_set (m_editline, EL_BIND, "-a", "[\\^", "lldb-revert-line", NULL);
+ }
+ }
}
-FILE *
-Editline::GetOutputFile ()
+//------------------------------------------------------------------
+// Editline public methods
+//------------------------------------------------------------------
+
+Editline *
+Editline::InstanceFor (EditLine * editline)
{
- return GetFilePointer (m_editline, 1);
+ Editline * editor;
+ el_get (editline, EL_CLIENTDATA, &editor);
+ return editor;
}
-FILE *
-Editline::GetErrorFile ()
+Editline::Editline (const char * editline_name, FILE * input_file, FILE * output_file, FILE * error_file, bool color_prompts) :
+ m_editor_status (EditorStatus::Complete),
+ m_color_prompts(color_prompts),
+ m_input_file (input_file),
+ m_output_file (output_file),
+ m_error_file (error_file),
+ m_input_connection (fileno(input_file), false)
{
- return GetFilePointer (m_editline, 2);
+ // Get a shared history instance
+ m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name;
+ m_history_sp = EditlineHistory::GetHistory (m_editor_name);
}
-const char *
-Editline::GetPrompt()
+Editline::~Editline()
{
- if (m_prompt_with_line_numbers && m_lines_curr_line > 0)
+ if (m_editline)
{
- StreamString strm;
- strm.Printf("%3u: ", m_lines_curr_line);
- m_lines_prompt = std::move(strm.GetString());
- return m_lines_prompt.c_str();
- }
- else
- {
- return m_prompt.c_str();
+ // Disable edit mode to stop the terminal from flushing all input
+ // during the call to el_end() since we expect to have multiple editline
+ // instances in this program.
+ el_set (m_editline, EL_EDITMODE, 0);
+ el_end (m_editline);
+ m_editline = nullptr;
}
+
+ // EditlineHistory objects are sometimes shared between multiple
+ // Editline instances with the same program name. So just release
+ // our shared pointer and if we are the last owner, it will save the
+ // history to the history save file automatically.
+ m_history_sp.reset();
}
void
-Editline::SetPrompt (const char *p)
+Editline::SetPrompt (const char * prompt)
{
- if (p && p[0])
- m_prompt = p;
- else
- m_prompt.clear();
- size_t start_pos = 0;
- size_t escape_pos;
- while ((escape_pos = m_prompt.find('\033', start_pos)) != std::string::npos)
- {
- m_prompt.insert(escape_pos, 1, k_prompt_escape_char);
- start_pos += 2;
- }
+ m_set_prompt = prompt == nullptr ? "" : prompt;
}
-FILE *
-Editline::GetFilePointer (::EditLine *e, int fd)
+void
+Editline::SetContinuationPrompt (const char * continuation_prompt)
{
- FILE *file_ptr = NULL;
- if (e && ::el_get(e, EL_GETFP, fd, &file_ptr) == 0)
- return file_ptr;
- return NULL;
+ m_set_continuation_prompt = continuation_prompt == nullptr ? "" : continuation_prompt;
}
-unsigned char
-Editline::CallbackEditPrevLine (::EditLine *e, int ch)
+void
+Editline::TerminalSizeChanged()
{
- Editline *editline = GetClientData (e);
- if (editline->m_lines_curr_line > 1)
+ if (m_editline != nullptr)
{
- editline->m_lines_command = Command::EditPrevLine;
- return CC_NEWLINE;
+ el_resize (m_editline);
+ int columns;
+ // Despite the man page claiming non-zero indicates success, it's actually zero
+ if (el_get (m_editline, EL_GETTC, "co", &columns) == 0)
+ {
+ m_terminal_width = columns;
+ if (m_current_line_rows != -1)
+ {
+ const LineInfoW * info = el_wline (m_editline);
+ int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth());
+ m_current_line_rows = (lineLength / columns) + 1;
+ }
+ }
+ else
+ {
+ m_terminal_width = INT_MAX;
+ m_current_line_rows = 1;
+ }
}
- return CC_ERROR;
}
-unsigned char
-Editline::CallbackEditNextLine (::EditLine *e, int ch)
+
+const char *
+Editline::GetPrompt()
{
- Editline *editline = GetClientData (e);
- if (editline->m_lines_curr_line < editline->m_lines_max_line)
- {
- editline->m_lines_command = Command::EditNextLine;
- return CC_NEWLINE;
- }
- return CC_ERROR;
+ return m_set_prompt.c_str();
}
-unsigned char
-Editline::CallbackComplete (::EditLine *e, int ch)
+uint32_t
+Editline::GetCurrentLine()
{
- Editline *editline = GetClientData (e);
- if (editline)
- return editline->HandleCompletion (ch);
- return CC_ERROR;
+ return m_current_line_index;
}
-const char *
-Editline::GetPromptCallback (::EditLine *e)
+void
+Editline::Hide()
{
- Editline *editline = GetClientData (e);
- if (editline)
- return editline->GetPrompt();
- return "";
+ // 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);
+ }
}
-int
-Editline::GetCharFromInputFileCallback (EditLine *e, char *c)
+void
+Editline::Refresh()
{
- Editline *editline = GetClientData (e);
- if (editline && editline->m_got_eof == false)
+ if (m_editor_status == EditorStatus::Editing)
{
- FILE *f = editline->GetInputFile();
- if (f == NULL)
- {
- editline->m_got_eof = true;
- return 0;
- }
-
-
- while (1)
- {
- lldb::ConnectionStatus status = eConnectionStatusSuccess;
- char ch = 0;
- // When we start to call el_gets() the editline library needs to
- // output the prompt
- editline->m_getting_char.SetValue(true, eBroadcastAlways);
- const size_t n = editline->m_file.Read(&ch, 1, UINT32_MAX, status, NULL);
- editline->m_getting_char.SetValue(false, eBroadcastAlways);
- if (n)
- {
- if (ch == '\x04')
- {
- // Only turn a CTRL+D into a EOF if we receive the
- // CTRL+D an empty line, otherwise it will forward
- // delete the character at the cursor
- const LineInfo *line_info = ::el_line(e);
- if (line_info != NULL &&
- line_info->buffer == line_info->cursor &&
- line_info->cursor == line_info->lastchar)
- {
- editline->m_got_eof = true;
- break;
- }
- }
-
- if (status == eConnectionStatusEndOfFile)
- {
- editline->m_got_eof = true;
- break;
- }
- else
- {
- *c = ch;
- return 1;
- }
- }
- else
- {
- switch (status)
- {
- case eConnectionStatusInterrupted:
- editline->m_interrupted = true;
- *c = '\n';
- return 1;
-
- case eConnectionStatusSuccess: // Success
- break;
-
- case eConnectionStatusError: // Check GetError() for details
- case eConnectionStatusTimedOut: // Request timed out
- case eConnectionStatusEndOfFile: // End-of-file encountered
- case eConnectionStatusNoConnection: // No connection
- case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
- editline->m_got_eof = true;
- break;
- }
- }
- }
+ DisplayInput();
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
}
- return 0;
}
-void
-Editline::Hide ()
+bool
+Editline::Interrupt()
{
- if (m_getting_line)
+ if (m_editor_status == EditorStatus::Editing)
{
- // If we are getting a line, we might have started to call el_gets() and
- // it might be printing the prompt. Here we make sure we are actually getting
- // a character. This way we know the entire prompt has been printed.
- TimeValue timeout = TimeValue::Now();
- timeout.OffsetWithSeconds(1);
- if (m_getting_char.WaitForValueEqualTo(true, &timeout))
- {
- FILE *out_file = GetOutputFile();
- if (out_file)
- {
- const LineInfo *line_info = ::el_line(m_editline);
- if (line_info)
- ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer));
- }
- }
+ return m_input_connection.InterruptRead();
}
+ return false; // Interrupt not handled as we weren't getting a line or lines
}
+void
+Editline::SetAutoCompleteCallback (CompleteCallbackType callback, void * baton)
+{
+ m_completion_callback = callback;
+ m_completion_callback_baton = baton;
+}
void
-Editline::Refresh()
+Editline::SetIsInputCompleteCallback (IsInputCompleteCallbackType callback, void * baton)
+{
+ m_is_input_complete_callback = callback;
+ m_is_input_complete_callback_baton = baton;
+}
+
+bool
+Editline::SetFixIndentationCallback (FixIndentationCallbackType callback,
+ void * baton,
+ const char * indent_chars)
{
- if (m_getting_line)
+ m_fix_indentation_callback = callback;
+ m_fix_indentation_callback_baton = baton;
+ m_fix_indentation_callback_chars = indent_chars;
+ return false;
+}
+
+bool
+Editline::GetLine (std::string &line, bool &interrupted)
+{
+ ConfigureEditor (false);
+ m_input_lines = std::vector<EditLineStringType>();
+ m_input_lines.insert (m_input_lines.begin(), EditLineConstString(""));
+
+ SetCurrentLine (0);
+ m_in_history = false;
+ m_editor_status = EditorStatus::Editing;
+ m_editor_getting_char = false;
+ m_revert_cursor_index = -1;
+
+ int count;
+ auto input = el_wgets (m_editline, &count);
+
+ interrupted = m_editor_status == EditorStatus::Interrupted;
+ if (!interrupted)
{
- // If we are getting a line, we might have started to call el_gets() and
- // it might be printing the prompt. Here we make sure we are actually getting
- // a character. This way we know the entire prompt has been printed.
- TimeValue timeout = TimeValue::Now();
- timeout.OffsetWithSeconds(1);
- if (m_getting_char.WaitForValueEqualTo(true, &timeout))
+ if (input == nullptr)
{
- ::el_set (m_editline, EL_REFRESH);
+ fprintf (m_output_file, "\n");
+ m_editor_status = EditorStatus::EndOfInput;
+ }
+ else
+ {
+ m_history_sp->Enter (input);
+#if LLDB_EDITLINE_USE_WCHAR
+ line = m_utf8conv.to_bytes (SplitLines (input)[0]);
+#else
+ line = SplitLines (input)[0];
+#endif
+ m_editor_status = EditorStatus::Complete;
}
}
+ return m_editor_status != EditorStatus::EndOfInput;
}
bool
-Editline::Interrupt ()
+Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted)
{
- m_interrupted = true;
- if (m_getting_line || m_lines_curr_line > 0)
- return m_file.InterruptRead();
- return false; // Interrupt not handled as we weren't getting a line or lines
+ ConfigureEditor (true);
+
+ // Print the initial input lines, then move the cursor back up to the start of input
+ SetBaseLineNumber (first_line_number);
+ m_input_lines = std::vector<EditLineStringType>();
+ m_input_lines.insert (m_input_lines.begin(), EditLineConstString(""));
+
+ // 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;
+ while (m_editor_status == EditorStatus::Editing)
+ {
+ int count;
+ m_current_line_rows = -1;
+ el_wpush (m_editline, EditLineConstString("\x1b[^")); // Revert to the existing line content
+ el_wgets (m_editline, &count);
+ }
+
+ interrupted = m_editor_status == EditorStatus::Interrupted;
+ if (!interrupted)
+ {
+ // Save the completed entry in history before returning
+ m_history_sp->Enter (CombineLines (m_input_lines).c_str());
+
+ lines = GetInputAsStringList();
+ }
+ return m_editor_status != EditorStatus::EndOfInput;
}
diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp
index 50513af2dc14..c3c77835ce86 100644
--- a/source/Host/common/File.cpp
+++ b/source/Host/common/File.cpp
@@ -896,7 +896,7 @@ File::CalculateInteractiveAndTerminal ()
{
m_is_interactive = eLazyBoolNo;
m_is_real_terminal = eLazyBoolNo;
-#ifdef _WIN32
+#if (defined(_WIN32) || defined(__ANDROID_NDK__))
if (_isatty(fd))
{
m_is_interactive = eLazyBoolYes;
diff --git a/source/Host/common/FileSpec.cpp b/source/Host/common/FileSpec.cpp
index 8c4014c074f5..0af0556d30c9 100644
--- a/source/Host/common/FileSpec.cpp
+++ b/source/Host/common/FileSpec.cpp
@@ -56,7 +56,8 @@ GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
}
// Resolves the username part of a path of the form ~user/other/directories, and
-// writes the result into dst_path.
+// 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.
void
FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path)
{
@@ -66,9 +67,9 @@ FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path)
llvm::StringRef path_str(path.data());
size_t slash_pos = path_str.find_first_of("/", 1);
- if (slash_pos == 1)
+ if (slash_pos == 1 || path.size() == 1)
{
- // A path of the form ~/ resolves to the current user's home dir
+ // A path of ~/ resolves to the current user's home dir
llvm::SmallString<64> home_dir;
if (!llvm::sys::path::home_directory(home_dir))
return;
@@ -166,10 +167,10 @@ FileSpec::Resolve (llvm::SmallVectorImpl<char> &path)
llvm::sys::fs::make_absolute(path);
}
-FileSpec::FileSpec()
- : m_directory()
- , m_filename()
- , m_syntax(FileSystem::GetNativePathSyntax())
+FileSpec::FileSpec() :
+ m_directory(),
+ m_filename(),
+ m_syntax(FileSystem::GetNativePathSyntax())
{
}
@@ -180,7 +181,8 @@ FileSpec::FileSpec()
FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) :
m_directory(),
m_filename(),
- m_is_resolved(false)
+ m_is_resolved(false),
+ m_syntax(syntax)
{
if (pathname && pathname[0])
SetFile(pathname, resolve_path, syntax);
@@ -266,14 +268,18 @@ FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax)
return;
llvm::SmallString<64> normalized(pathname);
- Normalize(normalized, syntax);
if (resolve)
{
FileSpec::Resolve (normalized);
m_is_resolved = true;
}
-
+
+ // Only normalize after resolving the path. Resolution will modify the path
+ // string, potentially adding wrong kinds of slashes to the path, that need
+ // to be re-normalized.
+ Normalize(normalized, syntax);
+
llvm::StringRef resolve_path_ref(normalized.c_str());
llvm::StringRef filename_ref = llvm::sys::path::filename(resolve_path_ref);
if (!filename_ref.empty())
@@ -446,15 +452,129 @@ FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full)
}
bool
-FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full)
+FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full, bool remove_backups)
{
if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty()))
return a.m_filename == b.m_filename;
- else
+ else if (remove_backups == false)
return a == b;
+ else
+ {
+ if (a.m_filename != b.m_filename)
+ return false;
+ if (a.m_directory == b.m_directory)
+ return true;
+ ConstString a_without_dots;
+ ConstString b_without_dots;
+
+ RemoveBackupDots (a.m_directory, a_without_dots);
+ RemoveBackupDots (b.m_directory, b_without_dots);
+ return a_without_dots == b_without_dots;
+ }
}
+void
+FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &result_const_str)
+{
+ const char *input = input_const_str.GetCString();
+ result_const_str.Clear();
+ if (!input || input[0] == '\0')
+ return;
+
+ const char win_sep = '\\';
+ const char unix_sep = '/';
+ char found_sep;
+ const char *win_backup = "\\..";
+ const char *unix_backup = "/..";
+
+ bool is_win = false;
+
+ // Determine the platform for the path (win or unix):
+
+ if (input[0] == win_sep)
+ is_win = true;
+ else if (input[0] == unix_sep)
+ is_win = false;
+ else if (input[1] == ':')
+ is_win = true;
+ else if (strchr(input, unix_sep) != nullptr)
+ is_win = false;
+ else if (strchr(input, win_sep) != nullptr)
+ is_win = true;
+ else
+ {
+ // No separators at all, no reason to do any work here.
+ result_const_str = input_const_str;
+ return;
+ }
+
+ llvm::StringRef backup_sep;
+ if (is_win)
+ {
+ found_sep = win_sep;
+ backup_sep = win_backup;
+ }
+ else
+ {
+ found_sep = unix_sep;
+ backup_sep = unix_backup;
+ }
+
+ llvm::StringRef input_ref(input);
+ llvm::StringRef curpos(input);
+
+ bool had_dots = false;
+ std::string result;
+
+ while (1)
+ {
+ // Start of loop
+ llvm::StringRef before_sep;
+ std::pair<llvm::StringRef, llvm::StringRef> around_sep = curpos.split(backup_sep);
+
+ before_sep = around_sep.first;
+ curpos = around_sep.second;
+
+ if (curpos.empty())
+ {
+ if (had_dots)
+ {
+ if (!before_sep.empty())
+ {
+ result.append(before_sep.data(), before_sep.size());
+ }
+ }
+ break;
+ }
+ had_dots = true;
+ unsigned num_backups = 1;
+ while (curpos.startswith(backup_sep))
+ {
+ num_backups++;
+ curpos = curpos.slice(backup_sep.size(), curpos.size());
+ }
+
+ size_t end_pos = before_sep.size();
+ while (num_backups-- > 0)
+ {
+ end_pos = before_sep.rfind(found_sep, end_pos);
+ if (end_pos == llvm::StringRef::npos)
+ {
+ result_const_str = input_const_str;
+ return;
+ }
+ }
+ result.append(before_sep.data(), end_pos);
+ }
+
+ if (had_dots)
+ result_const_str.SetCString(result.c_str());
+ else
+ result_const_str = input_const_str;
+
+ return;
+}
//------------------------------------------------------------------
// Dump the object to the supplied stream. If the object contains
@@ -502,7 +622,10 @@ FileSpec::ResolveExecutableLocation ()
if (file_cstr)
{
const std::string file_str (file_cstr);
- std::string path = llvm::sys::FindProgramByName (file_str);
+ llvm::ErrorOr<std::string> error_or_path = llvm::sys::findProgramByName (file_str);
+ if (!error_or_path)
+ return false;
+ std::string path = error_or_path.get();
llvm::StringRef dir_ref = llvm::sys::path::parent_path(path);
if (!dir_ref.empty())
{
@@ -946,6 +1069,8 @@ FileSpec::EnumerateDirectory
lldb_utility::CleanUp <DIR *, int> dir_path_dir(opendir(dir_path), NULL, closedir);
if (dir_path_dir.is_valid())
{
+ char dir_path_last_char = dir_path[strlen(dir_path) - 1];
+
long path_max = fpathconf (dirfd (dir_path_dir.get()), _PC_NAME_MAX);
#if defined (__APPLE_) && defined (__DARWIN_MAXPATHLEN)
if (path_max < __DARWIN_MAXPATHLEN)
@@ -990,7 +1115,14 @@ FileSpec::EnumerateDirectory
if (call_callback)
{
char child_path[PATH_MAX];
- const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name);
+
+ // 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))
{
// Don't resolve the file type or path
@@ -1208,18 +1340,31 @@ FileSpec::IsSourceImplementationFile () const
bool
FileSpec::IsRelativeToCurrentWorkingDirectory () const
{
- const char *directory = m_directory.GetCString();
- if (directory && directory[0])
+ const char *dir = m_directory.GetCString();
+ llvm::StringRef directory(dir ? dir : "");
+
+ if (directory.size() > 0)
{
- // If the path doesn't start with '/' or '~', return true
- switch (directory[0])
+ if (m_syntax == ePathSyntaxWindows)
{
- case '/':
- case '~':
- return false;
- default:
+ if (directory.size() >= 2 && directory[1] == ':')
+ return false;
+ if (directory[0] == '/')
+ return false;
return true;
}
+ else
+ {
+ // If the path doesn't start with '/' or '~', return true
+ switch (directory[0])
+ {
+ case '/':
+ case '~':
+ return false;
+ default:
+ return true;
+ }
+ }
}
else if (m_filename)
{
diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp
index 00c2fa37b383..c8daa175d1bd 100644
--- a/source/Host/common/Host.cpp
+++ b/source/Host/common/Host.cpp
@@ -14,11 +14,7 @@
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
-#ifdef _WIN32
-#include "lldb/Host/windows/windows.h"
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
+#ifndef _WIN32
#include <unistd.h>
#include <dlfcn.h>
#include <grp.h>
@@ -27,11 +23,6 @@
#include <sys/stat.h>
#endif
-#if !defined (__GNU__) && !defined (_WIN32)
-// Does not exist under GNU/HURD or Windows
-#include <sys/sysctl.h>
-#endif
-
#if defined (__APPLE__)
#include <mach/mach_port.h>
#include <mach/mach_init.h>
@@ -39,7 +30,9 @@
#endif
#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) || defined(__NetBSD__)
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
#include <spawn.h>
+#endif
#include <sys/wait.h>
#include <sys/syscall.h>
#endif
@@ -51,33 +44,30 @@
// C++ includes
#include <limits>
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/ThreadSafeSTLMap.h"
-#include "lldb/Host/Config.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/Mutex.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/MonitoringProcessLauncher.h"
+#include "lldb/Host/ProcessLauncher.h"
+#include "lldb/Host/ThreadLauncher.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/Target/FileAction.h"
-#include "lldb/Target/Process.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Utility/CleanUp.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
+#if defined(_WIN32)
+#include "lldb/Host/windows/ProcessLauncherWindows.h"
+#else
+#include "lldb/Host/posix/ProcessLauncherPosix.h"
+#endif
#if defined (__APPLE__)
#ifndef _POSIX_SPAWN_DISABLE_ASLR
@@ -95,13 +85,6 @@ extern "C"
using namespace lldb;
using namespace lldb_private;
-// Define maximum thread name length
-#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__NetBSD__)
-uint32_t const Host::MAX_THREAD_NAME_LENGTH = 16;
-#else
-uint32_t const Host::MAX_THREAD_NAME_LENGTH = std::numeric_limits<uint32_t>::max ();
-#endif
-
#if !defined (__APPLE__) && !defined (_WIN32)
struct MonitorInfo
{
@@ -114,16 +97,9 @@ struct MonitorInfo
static thread_result_t
MonitorChildProcessThreadFunction (void *arg);
-lldb::thread_t
-Host::StartMonitoringChildProcess
-(
- Host::MonitorChildProcessCallback callback,
- void *callback_baton,
- lldb::pid_t pid,
- bool monitor_signals
-)
+HostThread
+Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
{
- lldb::thread_t thread = LLDB_INVALID_HOST_THREAD;
MonitorInfo * info_ptr = new MonitorInfo();
info_ptr->pid = pid;
@@ -132,26 +108,11 @@ Host::StartMonitoringChildProcess
info_ptr->monitor_signals = monitor_signals;
char thread_name[256];
-
- if (Host::MAX_THREAD_NAME_LENGTH <= 16)
- {
- // On some platforms, the thread name is limited to 16 characters. We need to
- // abbreviate there or the pid info would get truncated.
- ::snprintf (thread_name, sizeof(thread_name), "wait4(%" PRIu64 ")", pid);
- }
- else
- {
- ::snprintf (thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid);
- }
-
- thread = ThreadCreate (thread_name,
- MonitorChildProcessThreadFunction,
- info_ptr,
- NULL);
-
- return thread;
+ ::snprintf(thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid);
+ return ThreadLauncher::LaunchThread(thread_name, MonitorChildProcessThreadFunction, info_ptr, NULL);
}
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
//------------------------------------------------------------------
// Scoped class that will disable thread canceling when it is
// constructed, and exception safely restore the previous value it
@@ -166,7 +127,6 @@ public:
int err = ::pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &m_old_state);
if (err != 0)
m_old_state = -1;
-
}
~ScopedPThreadCancelDisabler()
@@ -179,6 +139,7 @@ public:
private:
int m_old_state; // Save the old cancelability state.
};
+#endif // __ANDROID_NDK__
static thread_result_t
MonitorChildProcessThreadFunction (void *arg)
@@ -212,11 +173,14 @@ MonitorChildProcessThreadFunction (void *arg)
log->Printf("%s ::wait_pid (pid = %" PRIi32 ", &status, options = %i)...", function, pid, options);
// Wait for all child processes
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
::pthread_testcancel ();
+#endif
// 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 (wait_pid == -1)
{
if (errno == EINTR)
@@ -261,7 +225,9 @@ MonitorChildProcessThreadFunction (void *arg)
// Scope for pthread_cancel_disabler
{
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
ScopedPThreadCancelDisabler pthread_cancel_disabler;
+#endif
log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
if (log)
@@ -349,6 +315,8 @@ Host::GetCurrentThreadID()
return thread_self;
#elif defined(__FreeBSD__)
return lldb::tid_t(pthread_getthreadid_np());
+#elif defined(__ANDROID_NDK__)
+ return lldb::tid_t(gettid());
#elif defined(__linux__)
return lldb::tid_t(syscall(SYS_gettid));
#else
@@ -429,11 +397,6 @@ Host::WillTerminate ()
#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined (__linux__) // see macosx/Host.mm
void
-Host::ThreadCreated (const char *thread_name)
-{
-}
-
-void
Host::Backtrace (Stream &strm, uint32_t max_frames)
{
// TODO: Is there a way to backtrace the current process on other systems?
@@ -448,101 +411,8 @@ Host::GetEnvironment (StringList &env)
#endif // #if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined (__linux__)
-struct HostThreadCreateInfo
-{
- std::string thread_name;
- thread_func_t thread_fptr;
- thread_arg_t thread_arg;
-
- HostThreadCreateInfo (const char *name, thread_func_t fptr, thread_arg_t arg) :
- thread_name (name ? name : ""),
- thread_fptr (fptr),
- thread_arg (arg)
- {
- }
-};
-
-static thread_result_t
-#ifdef _WIN32
-__stdcall
-#endif
-ThreadCreateTrampoline (thread_arg_t arg)
-{
- HostThreadCreateInfo *info = (HostThreadCreateInfo *)arg;
- Host::ThreadCreated (info->thread_name.c_str());
- thread_func_t thread_fptr = info->thread_fptr;
- thread_arg_t thread_arg = info->thread_arg;
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
- if (log)
- log->Printf("thread created");
-
- delete info;
- return thread_fptr (thread_arg);
-}
-
-lldb::thread_t
-Host::ThreadCreate
-(
- const char *thread_name,
- thread_func_t thread_fptr,
- thread_arg_t thread_arg,
- Error *error
-)
-{
- lldb::thread_t thread = LLDB_INVALID_HOST_THREAD;
-
- // Host::ThreadCreateTrampoline will delete this pointer for us.
- HostThreadCreateInfo *info_ptr = new HostThreadCreateInfo (thread_name, thread_fptr, thread_arg);
-
-#ifdef _WIN32
- thread = ::_beginthreadex(0, 0, ThreadCreateTrampoline, info_ptr, 0, NULL);
- int err = thread <= 0 ? GetLastError() : 0;
-#else
- int err = ::pthread_create (&thread, NULL, ThreadCreateTrampoline, info_ptr);
-#endif
- if (err == 0)
- {
- if (error)
- error->Clear();
- return thread;
- }
-
- if (error)
- error->SetError (err, eErrorTypePOSIX);
-
- return LLDB_INVALID_HOST_THREAD;
-}
-
#ifndef _WIN32
-bool
-Host::ThreadCancel (lldb::thread_t thread, Error *error)
-{
- int err = ::pthread_cancel (thread);
- if (error)
- error->SetError(err, eErrorTypePOSIX);
- return err == 0;
-}
-
-bool
-Host::ThreadDetach (lldb::thread_t thread, Error *error)
-{
- int err = ::pthread_detach (thread);
- if (error)
- error->SetError(err, eErrorTypePOSIX);
- return err == 0;
-}
-
-bool
-Host::ThreadJoin (lldb::thread_t thread, thread_result_t *thread_result_ptr, Error *error)
-{
- int err = ::pthread_join (thread, thread_result_ptr);
- if (error)
- error->SetError(err, eErrorTypePOSIX);
- return err == 0;
-}
-
lldb::thread_key_t
Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback)
{
@@ -563,99 +433,6 @@ Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value)
::pthread_setspecific (key, value);
}
-bool
-Host::SetThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name)
-{
-#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
- lldb::pid_t curr_pid = Host::GetCurrentProcessID();
- lldb::tid_t curr_tid = Host::GetCurrentThreadID();
- if (pid == LLDB_INVALID_PROCESS_ID)
- pid = curr_pid;
-
- if (tid == LLDB_INVALID_THREAD_ID)
- tid = curr_tid;
-
- // Set the pthread name if possible
- if (pid == curr_pid && tid == curr_tid)
- {
- if (::pthread_setname_np (name) == 0)
- return true;
- }
- return false;
-#elif defined (__FreeBSD__)
- lldb::pid_t curr_pid = Host::GetCurrentProcessID();
- lldb::tid_t curr_tid = Host::GetCurrentThreadID();
- if (pid == LLDB_INVALID_PROCESS_ID)
- pid = curr_pid;
-
- if (tid == LLDB_INVALID_THREAD_ID)
- tid = curr_tid;
-
- // Set the pthread name if possible
- if (pid == curr_pid && tid == curr_tid)
- {
- ::pthread_set_name_np (::pthread_self(), name);
- return true;
- }
- return false;
-#elif defined (__linux__) || defined (__GLIBC__)
- void *fn = dlsym (RTLD_DEFAULT, "pthread_setname_np");
- if (fn)
- {
- lldb::pid_t curr_pid = Host::GetCurrentProcessID();
- lldb::tid_t curr_tid = Host::GetCurrentThreadID();
- if (pid == LLDB_INVALID_PROCESS_ID)
- pid = curr_pid;
-
- if (tid == LLDB_INVALID_THREAD_ID)
- tid = curr_tid;
-
- if (pid == curr_pid && tid == curr_tid)
- {
- int (*pthread_setname_np_func)(pthread_t thread, const char *name);
- *reinterpret_cast<void **> (&pthread_setname_np_func) = fn;
-
- if (pthread_setname_np_func (::pthread_self(), name) == 0)
- return true;
- }
- }
- return false;
-#else
- return false;
-#endif
-}
-
-bool
-Host::SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid,
- const char *thread_name, size_t len)
-{
- std::unique_ptr<char[]> namebuf(new char[len+1]);
-
- // Thread names are coming in like '<lldb.comm.debugger.edit>' and
- // '<lldb.comm.debugger.editline>'. So just chopping the end of the string
- // off leads to a lot of similar named threads. Go through the thread name
- // and search for the last dot and use that.
- const char *lastdot = ::strrchr (thread_name, '.');
-
- if (lastdot && lastdot != thread_name)
- thread_name = lastdot + 1;
- ::strncpy (namebuf.get(), thread_name, len);
- namebuf[len] = 0;
-
- int namebuflen = strlen(namebuf.get());
- if (namebuflen > 0)
- {
- if (namebuf[namebuflen - 1] == '(' || namebuf[namebuflen - 1] == '>')
- {
- // Trim off trailing '(' and '>' characters for a bit more cleanup.
- namebuflen--;
- namebuf[namebuflen] = 0;
- }
- return Host::SetThreadName (pid, tid, namebuf.get());
- }
- return false;
-}
-
#endif
#if !defined (__APPLE__) // see Host.mm
@@ -680,12 +457,16 @@ FileSpec
Host::GetModuleFileSpecForHostAddress (const void *host_addr)
{
FileSpec module_filespec;
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
Dl_info info;
if (::dladdr (host_addr, &info))
{
if (info.dli_fname)
module_filespec.SetFile(info.dli_fname, true);
}
+#else
+ assert(false && "dladdr() not supported on Android");
+#endif
return module_filespec;
}
@@ -699,28 +480,6 @@ Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
}
#endif
-lldb::TargetSP
-Host::GetDummyTarget (lldb_private::Debugger &debugger)
-{
- static TargetSP g_dummy_target_sp;
-
- // FIXME: Maybe the dummy target should be per-Debugger
- if (!g_dummy_target_sp || !g_dummy_target_sp->IsValid())
- {
- ArchSpec arch(Target::GetDefaultArchitecture());
- if (!arch.IsValid())
- arch = HostInfo::GetArchitecture();
- Error err = debugger.GetTargetList().CreateTarget(debugger,
- NULL,
- arch.GetTriple().getTriple().c_str(),
- false,
- NULL,
- g_dummy_target_sp);
- }
-
- return g_dummy_target_sp;
-}
-
struct ShellInfo
{
ShellInfo () :
@@ -770,14 +529,15 @@ Host::RunShellCommand (const char *command,
int *signo_ptr,
std::string *command_output_ptr,
uint32_t timeout_sec,
- const char *shell)
+ bool run_in_default_shell)
{
Error error;
ProcessLaunchInfo launch_info;
- if (shell && shell[0])
+ launch_info.SetArchitecture(HostInfo::GetArchitecture());
+ if (run_in_default_shell)
{
// Run the command in a shell
- launch_info.SetShell(shell);
+ launch_info.SetShell(HostInfo::GetDefaultShell());
launch_info.GetArguments().AppendArgument(command);
const bool localhost = true;
const bool will_debug = false;
@@ -798,9 +558,8 @@ Host::RunShellCommand (const char *command,
if (working_dir)
launch_info.SetWorkingDirectory(working_dir);
- char output_file_path_buffer[PATH_MAX];
- const char *output_file_path = NULL;
-
+ llvm::SmallString<PATH_MAX> output_file_path;
+
if (command_output_ptr)
{
// Create a temporary file to get the stdout/stderr and redirect the
@@ -809,21 +568,19 @@ Host::RunShellCommand (const char *command,
FileSpec tmpdir_file_spec;
if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
{
- tmpdir_file_spec.AppendPathComponent("lldb-shell-output.XXXXXX");
- strncpy(output_file_path_buffer, tmpdir_file_spec.GetPath().c_str(), sizeof(output_file_path_buffer));
+ tmpdir_file_spec.AppendPathComponent("lldb-shell-output.%%%%%%");
+ llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath().c_str(), output_file_path);
}
else
{
- strncpy(output_file_path_buffer, "/tmp/lldb-shell-output.XXXXXX", sizeof(output_file_path_buffer));
+ llvm::sys::fs::createTemporaryFile("lldb-shell-output.%%%%%%", "", output_file_path);
}
-
- output_file_path = ::mktemp(output_file_path_buffer);
}
launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false);
- if (output_file_path)
+ if (!output_file_path.empty())
{
- launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_path, false, true);
+ launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_path.c_str(), false, true);
launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO);
}
else
@@ -882,7 +639,7 @@ Host::RunShellCommand (const char *command,
if (command_output_ptr)
{
command_output_ptr->clear();
- FileSpec file_spec(output_file_path, File::eOpenOptionRead);
+ FileSpec file_spec(output_file_path.c_str(), File::eOpenOptionRead);
uint64_t file_size = file_spec.GetByteSize();
if (file_size > 0)
{
@@ -901,8 +658,9 @@ Host::RunShellCommand (const char *command,
shell_info->can_delete.SetValue(true, eBroadcastAlways);
}
- if (output_file_path)
- ::unlink (output_file_path);
+ FileSpec output_file_spec(output_file_path.c_str(), false);
+ if (FileSystem::GetFileExists(output_file_spec))
+ FileSystem::Unlink(output_file_path.c_str());
// 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...
@@ -914,13 +672,13 @@ Host::RunShellCommand (const char *command,
// systems
#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__)
-
// this method needs to be visible to macosx/Host.cpp and
// common/Host.cpp.
short
-Host::GetPosixspawnFlags (ProcessLaunchInfo &launch_info)
+Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info)
{
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
#if defined (__APPLE__)
@@ -963,12 +721,17 @@ Host::GetPosixspawnFlags (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, ProcessLaunchInfo &launch_info, ::pid_t &pid)
+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;
@@ -1086,6 +849,7 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
#endif
}
+ ::pid_t result_pid = LLDB_INVALID_PROCESS_ID;
const size_t num_file_actions = launch_info.GetNumFileActions ();
if (num_file_actions > 0)
{
@@ -1110,21 +874,13 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
}
}
- error.SetError (::posix_spawnp (&pid,
- exe_path,
- &file_actions,
- &attr,
- argv,
- envp),
- eErrorTypePOSIX);
+ error.SetError(::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), eErrorTypePOSIX);
if (error.Fail() || log)
{
- error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )",
- pid, exe_path, static_cast<void*>(&file_actions),
- static_cast<void*>(&attr),
- reinterpret_cast<const void*>(argv),
- reinterpret_cast<const void*>(envp));
+ error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", result_pid,
+ exe_path, static_cast<void *>(&file_actions), static_cast<void *>(&attr), reinterpret_cast<const void *>(argv),
+ reinterpret_cast<const void *>(envp));
if (log)
{
for (int ii=0; argv[ii]; ++ii)
@@ -1135,20 +891,13 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
}
else
{
- error.SetError (::posix_spawnp (&pid,
- exe_path,
- NULL,
- &attr,
- argv,
- envp),
- eErrorTypePOSIX);
+ error.SetError(::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp), eErrorTypePOSIX);
if (error.Fail() || log)
{
error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )",
- pid, exe_path, static_cast<void*>(&attr),
- reinterpret_cast<const void*>(argv),
- reinterpret_cast<const void*>(envp));
+ result_pid, exe_path, static_cast<void *>(&attr), reinterpret_cast<const void *>(argv),
+ reinterpret_cast<const void *>(envp));
if (log)
{
for (int ii=0; argv[ii]; ++ii)
@@ -1156,6 +905,7 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
}
}
}
+ pid = result_pid;
if (working_dir)
{
@@ -1171,6 +921,9 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
}
#endif
}
+#else
+ error.SetErrorString("Host::LaunchProcessPosixSpawn() not supported on Android");
+#endif
return error;
}
@@ -1178,6 +931,7 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
bool
Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log *log, Error &error)
{
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
if (info == NULL)
return false;
@@ -1240,97 +994,40 @@ 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
-
-#if 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,
// FreeBSD and NetBSD.
Error
Host::LaunchProcess (ProcessLaunchInfo &launch_info)
{
- Error error;
- char exe_path[PATH_MAX];
-
- PlatformSP host_platform_sp (Platform::GetDefaultPlatform ());
-
- const ArchSpec &arch_spec = launch_info.GetArchitecture();
-
- FileSpec exe_spec(launch_info.GetExecutableFile());
-
- FileSpec::FileType file_type = exe_spec.GetFileType();
- if (file_type != FileSpec::eFileTypeRegular)
- {
- lldb::ModuleSP exe_module_sp;
- error = host_platform_sp->ResolveExecutable (exe_spec,
- arch_spec,
- exe_module_sp,
- NULL);
-
- if (error.Fail())
- return error;
-
- if (exe_module_sp)
- exe_spec = exe_module_sp->GetFileSpec();
- }
-
- if (exe_spec.Exists())
- {
- exe_spec.GetPath (exe_path, sizeof(exe_path));
- }
- else
- {
- launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path));
- error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path);
- return error;
- }
-
- assert(!launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY));
-
- ::pid_t pid = LLDB_INVALID_PROCESS_ID;
-
- error = LaunchProcessPosixSpawn(exe_path, launch_info, pid);
+ std::unique_ptr<ProcessLauncher> delegate_launcher;
+#if defined(_WIN32)
+ delegate_launcher.reset(new ProcessLauncherWindows());
+#else
+ delegate_launcher.reset(new ProcessLauncherPosix());
+#endif
+ MonitoringProcessLauncher launcher(std::move(delegate_launcher));
- if (pid != LLDB_INVALID_PROCESS_ID)
- {
- // If all went well, then set the process ID into the launch info
- launch_info.SetProcessID(pid);
+ Error error;
+ HostProcess process = launcher.LaunchProcess(launch_info, error);
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ // TODO(zturner): It would be better if the entire HostProcess were returned instead of writing
+ // it into this structure.
+ launch_info.SetProcessID(process.GetProcessId());
- // Make sure we reap any processes we spawn or we will have zombies.
- if (!launch_info.MonitorProcess())
- {
- const bool monitor_signals = false;
- StartMonitoringChildProcess (Process::SetProcessExitStatus,
- NULL,
- pid,
- monitor_signals);
- if (log)
- log->PutCString ("monitored child process with default Process::SetProcessExitStatus.");
- }
- else
- {
- if (log)
- log->PutCString ("monitored child process with user-specified process monitor.");
- }
- }
- else
- {
- // Invalid process ID, something didn't go well
- if (error.Success())
- error.SetErrorString ("process launch failed for unknown reasons");
- }
return error;
}
-
#endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
#ifndef _WIN32
-
void
Host::Kill(lldb::pid_t pid, int signo)
{
diff --git a/source/Host/common/HostInfoBase.cpp b/source/Host/common/HostInfoBase.cpp
index 4eb43bfaf6ff..d65b79698384 100644
--- a/source/Host/common/HostInfoBase.cpp
+++ b/source/Host/common/HostInfoBase.cpp
@@ -18,7 +18,9 @@
#include "lldb/Host/HostInfoBase.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Host.h"
+#include "llvm/Support/raw_ostream.h"
#include <thread>
@@ -54,6 +56,7 @@ struct HostInfoBaseFields
FileSpec m_lldb_support_exe_dir;
FileSpec m_lldb_headers_dir;
FileSpec m_lldb_python_dir;
+ FileSpec m_lldb_clang_resource_dir;
FileSpec m_lldb_system_plugin_dir;
FileSpec m_lldb_user_plugin_dir;
FileSpec m_lldb_tmp_dir;
@@ -94,6 +97,12 @@ HostInfoBase::GetNumberCPUS()
return g_fields->m_number_cpus;
}
+uint32_t
+HostInfoBase::GetMaxThreadNameLength()
+{
+ return 0;
+}
+
llvm::StringRef
HostInfoBase::GetVendorString()
{
@@ -190,6 +199,11 @@ HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec)
if (log)
log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str());
break;
+ case lldb::ePathTypeClangDir:
+ COMPUTE_LLDB_PATH(ComputeClangDirectory, g_fields->m_lldb_clang_resource_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", g_fields->m_lldb_clang_resource_dir.GetPath().c_str());
+ break;
case lldb::ePathTypeLLDBSystemPlugins:
COMPUTE_LLDB_PATH(ComputeSystemPluginsDirectory, g_fields->m_lldb_system_plugin_dir)
if (log)
@@ -252,19 +266,23 @@ HostInfoBase::ComputeTempFileDirectory(FileSpec &file_spec)
if (!tmpdir_cstr)
return false;
- StreamString pid_tmpdir;
- pid_tmpdir.Printf("%s/lldb", tmpdir_cstr);
- if (!FileSystem::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success())
+ FileSpec temp_file_spec(tmpdir_cstr, false);
+ temp_file_spec.AppendPathComponent("lldb");
+ if (!FileSystem::MakeDirectory(temp_file_spec.GetPath().c_str(), eFilePermissionsDirectoryDefault).Success())
return false;
- pid_tmpdir.Printf("/%" PRIu64, Host::GetCurrentProcessID());
- if (!FileSystem::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success())
+ 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())
return false;
// Make an atexit handler to clean up the process specify LLDB temp dir
// and all of its contents.
::atexit(CleanupProcessSpecificLLDBTempDir);
- file_spec.GetDirectory().SetCStringWithLength(pid_tmpdir.GetString().c_str(), pid_tmpdir.GetString().size());
+ file_spec.GetDirectory().SetCStringWithLength(final_path.c_str(), final_path.size());
return true;
}
@@ -283,6 +301,12 @@ HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec)
}
bool
+HostInfoBase::ComputeClangDirectory(FileSpec &file_spec)
+{
+ return false;
+}
+
+bool
HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec)
{
// TODO(zturner): Figure out how to compute the user plugins directory for all platforms.
diff --git a/source/Host/common/HostNativeThreadBase.cpp b/source/Host/common/HostNativeThreadBase.cpp
new file mode 100644
index 000000000000..9fea54d1e3fa
--- /dev/null
+++ b/source/Host/common/HostNativeThreadBase.cpp
@@ -0,0 +1,82 @@
+//===-- HostNativeThreadBase.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/Log.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/HostNativeThreadBase.h"
+#include "lldb/Host/ThisThread.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostNativeThreadBase::HostNativeThreadBase()
+ : m_thread(LLDB_INVALID_HOST_THREAD)
+ , m_result(0)
+{
+}
+
+HostNativeThreadBase::HostNativeThreadBase(thread_t thread)
+ : m_thread(thread)
+ , m_result(0)
+{
+}
+
+lldb::thread_t
+HostNativeThreadBase::GetSystemHandle() const
+{
+ return m_thread;
+}
+
+lldb::thread_result_t
+HostNativeThreadBase::GetResult() const
+{
+ return m_result;
+}
+
+bool
+HostNativeThreadBase::IsJoinable() const
+{
+ return m_thread != LLDB_INVALID_HOST_THREAD;
+}
+
+void
+HostNativeThreadBase::Reset()
+{
+ m_thread = LLDB_INVALID_HOST_THREAD;
+ m_result = 0;
+}
+
+lldb::thread_t
+HostNativeThreadBase::Release()
+{
+ lldb::thread_t result = m_thread;
+ m_thread = LLDB_INVALID_HOST_THREAD;
+ m_result = 0;
+
+ return result;
+}
+
+lldb::thread_result_t
+HostNativeThreadBase::ThreadCreateTrampoline(lldb::thread_arg_t arg)
+{
+ ThreadLauncher::HostThreadCreateInfo *info = (ThreadLauncher::HostThreadCreateInfo *)arg;
+ ThisThread::SetName(info->thread_name.c_str(), HostInfo::GetMaxThreadNameLength());
+
+ thread_func_t thread_fptr = info->thread_fptr;
+ thread_arg_t thread_arg = info->thread_arg;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf("thread created");
+
+ delete info;
+ return thread_fptr(thread_arg);
+}
diff --git a/source/Host/common/HostProcess.cpp b/source/Host/common/HostProcess.cpp
new file mode 100644
index 000000000000..58a214693a52
--- /dev/null
+++ b/source/Host/common/HostProcess.cpp
@@ -0,0 +1,65 @@
+//===-- HostProcess.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/HostNativeProcess.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/HostThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostProcess::HostProcess()
+ : m_native_process(new HostNativeProcess)
+{
+}
+
+HostProcess::HostProcess(lldb::process_t process)
+ : m_native_process(new HostNativeProcess(process))
+{
+}
+
+HostProcess::~HostProcess()
+{
+}
+
+Error HostProcess::Terminate()
+{
+ return m_native_process->Terminate();
+}
+
+Error HostProcess::GetMainModule(FileSpec &file_spec) const
+{
+ return m_native_process->GetMainModule(file_spec);
+}
+
+lldb::pid_t HostProcess::GetProcessId() const
+{
+ return m_native_process->GetProcessId();
+}
+
+bool HostProcess::IsRunning() const
+{
+ return m_native_process->IsRunning();
+}
+
+HostThread
+HostProcess::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals)
+{
+ return m_native_process->StartMonitoring(callback, callback_baton, monitor_signals);
+}
+
+HostNativeProcessBase &HostProcess::GetNativeProcess()
+{
+ return *m_native_process;
+}
+
+const HostNativeProcessBase &HostProcess::GetNativeProcess() const
+{
+ return *m_native_process;
+}
diff --git a/source/Host/common/HostThread.cpp b/source/Host/common/HostThread.cpp
new file mode 100644
index 000000000000..7757477126c4
--- /dev/null
+++ b/source/Host/common/HostThread.cpp
@@ -0,0 +1,78 @@
+//===-- HostThread.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/HostNativeThread.h"
+#include "lldb/Host/HostThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostThread::HostThread()
+ : m_native_thread(new HostNativeThread)
+{
+}
+
+HostThread::HostThread(lldb::thread_t thread)
+ : m_native_thread(new HostNativeThread(thread))
+{
+}
+
+Error
+HostThread::Join(lldb::thread_result_t *result)
+{
+ return m_native_thread->Join(result);
+}
+
+Error
+HostThread::Cancel()
+{
+ return m_native_thread->Cancel();
+}
+
+void
+HostThread::Reset()
+{
+ return m_native_thread->Reset();
+}
+
+lldb::thread_t
+HostThread::Release()
+{
+ return m_native_thread->Release();
+}
+
+bool
+HostThread::IsJoinable() const
+{
+ return m_native_thread->IsJoinable();
+}
+
+HostNativeThread &
+HostThread::GetNativeThread()
+{
+ return static_cast<HostNativeThread &>(*m_native_thread);
+}
+
+const HostNativeThread &
+HostThread::GetNativeThread() const
+{
+ return static_cast<const HostNativeThread &>(*m_native_thread);
+}
+
+lldb::thread_result_t
+HostThread::GetResult() const
+{
+ return m_native_thread->GetResult();
+}
+
+bool
+HostThread::EqualsThread(lldb::thread_t thread) const
+{
+ return m_native_thread->GetSystemHandle() == thread;
+}
diff --git a/source/Host/common/MonitoringProcessLauncher.cpp b/source/Host/common/MonitoringProcessLauncher.cpp
new file mode 100644
index 000000000000..0fad44a9ec08
--- /dev/null
+++ b/source/Host/common/MonitoringProcessLauncher.cpp
@@ -0,0 +1,102 @@
+//===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/MonitoringProcessLauncher.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+MonitoringProcessLauncher::MonitoringProcessLauncher(std::unique_ptr<ProcessLauncher> delegate_launcher)
+ : m_delegate_launcher(std::move(delegate_launcher))
+{
+}
+
+HostProcess
+MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error)
+{
+ ProcessLaunchInfo resolved_info(launch_info);
+
+ error.Clear();
+ char exe_path[PATH_MAX];
+
+ PlatformSP host_platform_sp(Platform::GetHostPlatform());
+
+ const ArchSpec &arch_spec = resolved_info.GetArchitecture();
+
+ FileSpec exe_spec(resolved_info.GetExecutableFile());
+
+ FileSpec::FileType file_type = exe_spec.GetFileType();
+ if (file_type != FileSpec::eFileTypeRegular)
+ {
+ ModuleSpec module_spec(exe_spec, arch_spec);
+ lldb::ModuleSP exe_module_sp;
+ error = host_platform_sp->ResolveExecutable(module_spec, exe_module_sp, NULL);
+
+ if (error.Fail())
+ return HostProcess();
+
+ if (exe_module_sp)
+ exe_spec = exe_module_sp->GetFileSpec();
+ }
+
+ if (exe_spec.Exists())
+ {
+ exe_spec.GetPath(exe_path, sizeof(exe_path));
+ }
+ else
+ {
+ resolved_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat("executable doesn't exist: '%s'", exe_path);
+ return HostProcess();
+ }
+
+ resolved_info.SetExecutableFile(exe_spec, false);
+ assert(!resolved_info.GetFlags().Test(eLaunchFlagLaunchInTTY));
+
+ HostProcess process = m_delegate_launcher->LaunchProcess(resolved_info, error);
+
+ if (process.GetProcessId() != LLDB_INVALID_PROCESS_ID)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ Host::MonitorChildProcessCallback callback = launch_info.GetMonitorProcessCallback();
+
+ void *baton = nullptr;
+ bool monitor_signals = false;
+ if (callback)
+ {
+ // If the ProcessLaunchInfo specified a callback, use that.
+ baton = launch_info.GetMonitorProcessBaton();
+ monitor_signals = launch_info.GetMonitorSignals();
+ }
+ else
+ {
+ callback = Process::SetProcessExitStatus;
+ }
+
+ process.StartMonitoring(callback, baton, monitor_signals);
+ if (log)
+ log->PutCString("started monitoring child process.");
+ }
+ else
+ {
+ // Invalid process ID, something didn't go well
+ if (error.Success())
+ error.SetErrorString("process launch failed for unknown reasons");
+ }
+ return process;
+}
diff --git a/source/Host/common/NativeProcessProtocol.cpp b/source/Host/common/NativeProcessProtocol.cpp
index b7a77266c58c..e192f19a8896 100644
--- a/source/Host/common/NativeProcessProtocol.cpp
+++ b/source/Host/common/NativeProcessProtocol.cpp
@@ -13,6 +13,7 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
#include "lldb/Target/NativeRegisterContext.h"
#include "NativeThreadProtocol.h"
@@ -44,6 +45,18 @@ NativeProcessProtocol::NativeProcessProtocol (lldb::pid_t pid) :
}
lldb_private::Error
+NativeProcessProtocol::Interrupt ()
+{
+ Error error;
+#if !defined (SIGSTOP)
+ error.SetErrorString ("local host does not support signaling");
+ return error;
+#else
+ return Signal (SIGSTOP);
+#endif
+}
+
+lldb_private::Error
NativeProcessProtocol::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info)
{
// Default: not implemented.
@@ -110,9 +123,8 @@ NativeProcessProtocol::GetThreadAtIndex (uint32_t idx)
}
NativeThreadProtocolSP
-NativeProcessProtocol::GetThreadByID (lldb::tid_t tid)
+NativeProcessProtocol::GetThreadByIDUnlocked (lldb::tid_t tid)
{
- Mutex::Locker locker (m_threads_mutex);
for (auto thread_sp : m_threads)
{
if (thread_sp->GetID() == tid)
@@ -121,6 +133,13 @@ NativeProcessProtocol::GetThreadByID (lldb::tid_t tid)
return NativeThreadProtocolSP ();
}
+NativeThreadProtocolSP
+NativeProcessProtocol::GetThreadByID (lldb::tid_t tid)
+{
+ Mutex::Locker locker (m_threads_mutex);
+ return GetThreadByIDUnlocked (tid);
+}
+
bool
NativeProcessProtocol::IsAlive () const
{
diff --git a/source/Host/common/NativeProcessProtocol.h b/source/Host/common/NativeProcessProtocol.h
index 035a264e172e..19d8f353b26f 100644
--- a/source/Host/common/NativeProcessProtocol.h
+++ b/source/Host/common/NativeProcessProtocol.h
@@ -59,17 +59,25 @@ namespace lldb_private
//------------------------------------------------------------------
/// Sends a process a UNIX signal \a signal.
///
- /// Implementer note: the WillSignal ()/DidSignal () calls
- /// from the Process class are not replicated here since no
- /// concrete classes implemented any behavior for those and
- /// put all the work in DoSignal (...).
- ///
/// @return
/// Returns an error object.
//------------------------------------------------------------------
virtual Error
Signal (int signo) = 0;
+ //------------------------------------------------------------------
+ /// Tells a process to interrupt all operations as if by a Ctrl-C.
+ ///
+ /// The default implementation will send a local host's equivalent of
+ /// a SIGSTOP to the process via the NativeProcessProtocol::Signal()
+ /// operation.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ Interrupt ();
+
virtual Error
Kill () = 0;
@@ -296,7 +304,7 @@ namespace lldb_private
void
SetState (lldb::StateType state, bool notify_delegates = true);
- // Derived classes need not impelment this. It can be used as a
+ // Derived classes need not implement this. It can be used as a
// hook to clear internal caches that should be invalidated when
// stop ids change.
//
@@ -323,6 +331,9 @@ namespace lldb_private
void
NotifyDidExec ();
+ NativeThreadProtocolSP
+ GetThreadByIDUnlocked (lldb::tid_t tid);
+
private:
void
diff --git a/source/Host/common/NativeThreadProtocol.h b/source/Host/common/NativeThreadProtocol.h
index 9b404be500b9..15ecffe8b82d 100644
--- a/source/Host/common/NativeThreadProtocol.h
+++ b/source/Host/common/NativeThreadProtocol.h
@@ -31,7 +31,7 @@ namespace lldb_private
{
}
- virtual const char *
+ virtual std::string
GetName() = 0;
virtual lldb::StateType
diff --git a/source/Host/common/Pipe.cpp b/source/Host/common/Pipe.cpp
deleted file mode 100644
index 4db0e32c93b7..000000000000
--- a/source/Host/common/Pipe.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-//===-- Pipe.cpp ------------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/Pipe.h"
-
-#if defined(_WIN32)
-#include <io.h>
-#include <fcntl.h>
-#else
-#include <unistd.h>
-#endif
-
-using namespace lldb_private;
-
-int Pipe::kInvalidDescriptor = -1;
-
-enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
-
-Pipe::Pipe()
-{
- m_fds[READ] = Pipe::kInvalidDescriptor;
- m_fds[WRITE] = Pipe::kInvalidDescriptor;
-}
-
-Pipe::~Pipe()
-{
- Close();
-}
-
-bool
-Pipe::Open()
-{
- if (IsValid())
- return true;
-
-#ifdef _WIN32
- if (::_pipe(m_fds, 256, O_BINARY) == 0)
- return true;
-#else
- if (::pipe(m_fds) == 0)
- return true;
-#endif
- m_fds[READ] = Pipe::kInvalidDescriptor;
- m_fds[WRITE] = Pipe::kInvalidDescriptor;
- return false;
-}
-
-int
-Pipe::GetReadFileDescriptor() const
-{
- return m_fds[READ];
-}
-
-int
-Pipe::GetWriteFileDescriptor() const
-{
- return m_fds[WRITE];
-}
-
-int
-Pipe::ReleaseReadFileDescriptor()
-{
- const int fd = m_fds[READ];
- m_fds[READ] = Pipe::kInvalidDescriptor;
- return fd;
-}
-
-int
-Pipe::ReleaseWriteFileDescriptor()
-{
- const int fd = m_fds[WRITE];
- m_fds[WRITE] = Pipe::kInvalidDescriptor;
- return fd;
-}
-
-void
-Pipe::Close()
-{
- CloseReadFileDescriptor();
- CloseWriteFileDescriptor();
-}
-
-bool
-Pipe::ReadDescriptorIsValid() const
-{
- return m_fds[READ] != Pipe::kInvalidDescriptor;
-}
-
-bool
-Pipe::WriteDescriptorIsValid() const
-{
- return m_fds[WRITE] != Pipe::kInvalidDescriptor;
-}
-
-bool
-Pipe::IsValid() const
-{
- return ReadDescriptorIsValid() && WriteDescriptorIsValid();
-}
-
-bool
-Pipe::CloseReadFileDescriptor()
-{
- if (ReadDescriptorIsValid())
- {
- int err;
-#ifdef _WIN32
- err = _close(m_fds[READ]);
-#else
- err = close(m_fds[READ]);
-#endif
- m_fds[READ] = Pipe::kInvalidDescriptor;
- return err == 0;
- }
- return true;
-}
-
-bool
-Pipe::CloseWriteFileDescriptor()
-{
- if (WriteDescriptorIsValid())
- {
- int err;
-#ifdef _WIN32
- err = _close(m_fds[WRITE]);
-#else
- err = close(m_fds[WRITE]);
-#endif
- m_fds[WRITE] = Pipe::kInvalidDescriptor;
- return err == 0;
- }
- return true;
-}
-
-
-size_t
-Pipe::Read (void *buf, size_t num_bytes)
-{
- if (ReadDescriptorIsValid())
- {
- const int fd = GetReadFileDescriptor();
-#ifdef _WIN32
- return _read (fd, (char *)buf, num_bytes);
-#else
- return read (fd, buf, num_bytes);
-#endif
- }
- return 0; // Return 0 since errno won't be set if we didn't call read
-}
-
-size_t
-Pipe::Write (const void *buf, size_t num_bytes)
-{
- if (WriteDescriptorIsValid())
- {
- const int fd = GetWriteFileDescriptor();
-#ifdef _WIN32
- return _write (fd, (char *)buf, num_bytes);
-#else
- return write (fd, buf, num_bytes);
-#endif
- }
- return 0; // Return 0 since errno won't be set if we didn't call write
-}
-
diff --git a/source/Host/common/PipeBase.cpp b/source/Host/common/PipeBase.cpp
new file mode 100644
index 000000000000..a9d6e6f46c86
--- /dev/null
+++ b/source/Host/common/PipeBase.cpp
@@ -0,0 +1,27 @@
+//===-- source/Host/common/PipeBase.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/PipeBase.h"
+
+using namespace lldb_private;
+
+
+PipeBase::~PipeBase() = default;
+
+Error
+PipeBase::OpenAsWriter(llvm::StringRef name, bool child_process_inherit)
+{
+ return OpenAsWriterWithTimeout(name, child_process_inherit, std::chrono::microseconds::zero());
+}
+
+Error
+PipeBase::Read(void *buf, size_t size, size_t &bytes_read)
+{
+ return ReadWithTimeout(buf, size, std::chrono::microseconds::zero(), bytes_read);
+}
diff --git a/source/Host/common/Socket.cpp b/source/Host/common/Socket.cpp
index 31e3228497ec..a6118eef7b79 100644
--- a/source/Host/common/Socket.cpp
+++ b/source/Host/common/Socket.cpp
@@ -18,6 +18,14 @@
#include "lldb/Host/TimeValue.h"
#include "lldb/Interpreter/Args.h"
+#ifdef __ANDROID_NDK__
+#include <linux/tcp.h>
+#include <bits/error_constants.h>
+#include <asm-generic/errno-base.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#endif
+
#ifndef LLDB_DISABLE_POSIX
#include <arpa/inet.h>
#include <netdb.h>
@@ -40,6 +48,40 @@ typedef void * get_socket_option_arg_type;
const NativeSocket Socket::kInvalidSocketValue = -1;
#endif // #if defined(_WIN32)
+#ifdef __ANDROID__
+// Android does not have SUN_LEN
+#ifndef SUN_LEN
+#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path))
+#endif
+#endif // #ifdef __ANDROID__
+
+namespace {
+
+NativeSocket CreateSocket(const int domain, const int type, const int protocol, bool child_processes_inherit)
+{
+ auto socketType = type;
+#ifdef SOCK_CLOEXEC
+ if (!child_processes_inherit) {
+ socketType |= SOCK_CLOEXEC;
+ }
+#endif
+ return ::socket (domain, socketType, protocol);
+}
+
+NativeSocket Accept(NativeSocket sockfd, struct sockaddr *addr, socklen_t *addrlen, bool child_processes_inherit)
+{
+#ifdef SOCK_CLOEXEC
+ int flags = 0;
+ if (!child_processes_inherit) {
+ flags |= SOCK_CLOEXEC;
+ }
+ return ::accept4 (sockfd, addr, addrlen, flags);
+#else
+ return ::accept (sockfd, addr, addrlen);
+#endif
+}
+}
+
Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close)
: IOObject(eFDTypeSocket, should_close)
, m_protocol(protocol)
@@ -53,7 +95,7 @@ Socket::~Socket()
Close();
}
-Error Socket::TcpConnect(llvm::StringRef host_and_port, Socket *&socket)
+Error Socket::TcpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket)
{
// Store the result in a unique_ptr in case we error out, the memory will get correctly freed.
std::unique_ptr<Socket> final_socket;
@@ -71,7 +113,7 @@ Error Socket::TcpConnect(llvm::StringRef host_and_port, Socket *&socket)
return error;
// Create the socket
- sock = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ sock = CreateSocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, child_processes_inherit);
if (sock == kInvalidSocketValue)
{
// TODO: On Windows, use WSAGetLastError().
@@ -125,7 +167,7 @@ Error Socket::TcpConnect(llvm::StringRef host_and_port, Socket *&socket)
return error;
}
-Error Socket::TcpListen(llvm::StringRef host_and_port, Socket *&socket, Predicate<uint16_t>* predicate)
+Error Socket::TcpListen(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket, Predicate<uint16_t>* predicate)
{
std::unique_ptr<Socket> listen_socket;
NativeSocket listen_sock = kInvalidSocketValue;
@@ -134,7 +176,7 @@ Error Socket::TcpListen(llvm::StringRef host_and_port, Socket *&socket, Predicat
const sa_family_t family = AF_INET;
const int socktype = SOCK_STREAM;
const int protocol = IPPROTO_TCP;
- listen_sock = ::socket (family, socktype, protocol);
+ listen_sock = ::CreateSocket (family, socktype, protocol, child_processes_inherit);
if (listen_sock == kInvalidSocketValue)
{
error.SetErrorToErrno();
@@ -196,7 +238,7 @@ Error Socket::TcpListen(llvm::StringRef host_and_port, Socket *&socket, Predicat
return error;
}
-Error Socket::BlockingAccept(llvm::StringRef host_and_port, Socket *&socket)
+Error Socket::BlockingAccept(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket)
{
Error error;
std::string host_str;
@@ -235,7 +277,10 @@ Error Socket::BlockingAccept(llvm::StringRef host_and_port, Socket *&socket)
#endif
socklen_t accept_addr_len = sizeof accept_addr;
- int sock = ::accept (this->GetNativeSocket(), (struct sockaddr *)&accept_addr, &accept_addr_len);
+ int sock = Accept (this->GetNativeSocket(),
+ (struct sockaddr *)&accept_addr,
+ &accept_addr_len,
+ child_processes_inherit);
if (sock == kInvalidSocketValue)
{
@@ -280,7 +325,7 @@ Error Socket::BlockingAccept(llvm::StringRef host_and_port, Socket *&socket)
}
-Error Socket::UdpConnect(llvm::StringRef host_and_port, Socket *&send_socket, Socket *&recv_socket)
+Error Socket::UdpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket)
{
std::unique_ptr<Socket> final_send_socket;
std::unique_ptr<Socket> final_recv_socket;
@@ -300,7 +345,7 @@ Error Socket::UdpConnect(llvm::StringRef host_and_port, Socket *&send_socket, So
// Setup the receiving end of the UDP connection on this localhost
// on port zero. After we bind to port zero we can read the port.
- final_recv_fd = ::socket (AF_INET, SOCK_DGRAM, 0);
+ final_recv_fd = ::CreateSocket (AF_INET, SOCK_DGRAM, 0, child_processes_inherit);
if (final_recv_fd == kInvalidSocketValue)
{
// Socket creation failed...
@@ -351,9 +396,10 @@ Error Socket::UdpConnect(llvm::StringRef host_and_port, Socket *&send_socket, So
service_info_ptr != NULL;
service_info_ptr = service_info_ptr->ai_next)
{
- final_send_fd = ::socket (service_info_ptr->ai_family,
- service_info_ptr->ai_socktype,
- service_info_ptr->ai_protocol);
+ final_send_fd = ::CreateSocket (service_info_ptr->ai_family,
+ service_info_ptr->ai_socktype,
+ service_info_ptr->ai_protocol,
+ child_processes_inherit);
if (final_send_fd != kInvalidSocketValue)
{
@@ -380,7 +426,7 @@ Error Socket::UdpConnect(llvm::StringRef host_and_port, Socket *&send_socket, So
return error;
}
-Error Socket::UnixDomainConnect(llvm::StringRef name, Socket *&socket)
+Error Socket::UnixDomainConnect(llvm::StringRef name, bool child_processes_inherit, Socket *&socket)
{
Error error;
#ifndef LLDB_DISABLE_POSIX
@@ -388,7 +434,7 @@ Error Socket::UnixDomainConnect(llvm::StringRef name, Socket *&socket)
// Open the socket that was passed in as an option
struct sockaddr_un saddr_un;
- int fd = ::socket (AF_UNIX, SOCK_STREAM, 0);
+ int fd = ::CreateSocket (AF_UNIX, SOCK_STREAM, 0, child_processes_inherit);
if (fd == kInvalidSocketValue)
{
error.SetErrorToErrno();
@@ -417,7 +463,7 @@ Error Socket::UnixDomainConnect(llvm::StringRef name, Socket *&socket)
return error;
}
-Error Socket::UnixDomainAccept(llvm::StringRef name, Socket *&socket)
+Error Socket::UnixDomainAccept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket)
{
Error error;
#ifndef LLDB_DISABLE_POSIX
@@ -427,7 +473,7 @@ Error Socket::UnixDomainAccept(llvm::StringRef name, Socket *&socket)
NativeSocket listen_fd = kInvalidSocketValue;
NativeSocket socket_fd = kInvalidSocketValue;
- listen_fd = ::socket (AF_UNIX, SOCK_STREAM, 0);
+ listen_fd = ::CreateSocket (AF_UNIX, SOCK_STREAM, 0, child_processes_inherit);
if (listen_fd == kInvalidSocketValue)
{
error.SetErrorToErrno();
@@ -449,7 +495,7 @@ Error Socket::UnixDomainAccept(llvm::StringRef name, Socket *&socket)
{
if (::listen (listen_fd, 5) == 0)
{
- socket_fd = ::accept (listen_fd, NULL, 0);
+ socket_fd = Accept (listen_fd, NULL, 0, child_processes_inherit);
if (socket_fd > 0)
{
final_socket.reset(new Socket(socket_fd, ProtocolUnixDomain, true));
diff --git a/source/Host/common/SocketAddress.cpp b/source/Host/common/SocketAddress.cpp
index a952a83185fb..6231631934df 100644
--- a/source/Host/common/SocketAddress.cpp
+++ b/source/Host/common/SocketAddress.cpp
@@ -214,6 +214,8 @@ SocketAddress::getaddrinfo (const char *host,
int ai_protocol,
int ai_flags)
{
+ Clear ();
+
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = ai_family;
@@ -221,15 +223,17 @@ SocketAddress::getaddrinfo (const char *host,
hints.ai_protocol = ai_protocol;
hints.ai_flags = ai_flags;
+ bool result = false;
struct addrinfo *service_info_list = NULL;
int err = ::getaddrinfo (host, service, &hints, &service_info_list);
if (err == 0 && service_info_list)
+ {
*this = service_info_list;
- else
- Clear();
+ result = IsValid ();
+ }
:: freeaddrinfo (service_info_list);
- return IsValid();
+ return result;
}
diff --git a/source/Host/common/SoftwareBreakpoint.cpp b/source/Host/common/SoftwareBreakpoint.cpp
index fe2f504ebc71..d9d1fa67156f 100644
--- a/source/Host/common/SoftwareBreakpoint.cpp
+++ b/source/Host/common/SoftwareBreakpoint.cpp
@@ -119,6 +119,16 @@ SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, ll
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 what we read.
+ if (log)
+ {
+ 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));
+ }
+ }
+
// 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);
@@ -207,7 +217,7 @@ SoftwareBreakpoint::DoDisable ()
if (m_opcode_size > 0)
{
- // Clear a software breakoint instruction
+ // Clear a software breakpoint instruction
uint8_t curr_break_op [MAX_TRAP_OPCODE_SIZE];
bool break_op_found = false;
assert (m_opcode_size <= sizeof (curr_break_op));
@@ -265,7 +275,14 @@ SoftwareBreakpoint::DoDisable ()
{
// SUCCESS
if (log)
+ {
+ 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 " -- SUCCESS", __FUNCTION__, m_addr);
+ }
return error;
}
else
diff --git a/source/Host/common/ThisThread.cpp b/source/Host/common/ThisThread.cpp
new file mode 100644
index 000000000000..289ec780e9fb
--- /dev/null
+++ b/source/Host/common/ThisThread.cpp
@@ -0,0 +1,52 @@
+//===-- ThisThread.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/ThisThread.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+ThisThread::SetName(llvm::StringRef name, int max_length)
+{
+ std::string truncated_name(name.data());
+
+ // Thread names are coming in like '<lldb.comm.debugger.edit>' and
+ // '<lldb.comm.debugger.editline>'. So just chopping the end of the string
+ // off leads to a lot of similar named threads. Go through the thread name
+ // and search for the last dot and use that.
+
+ if (max_length > 0 && truncated_name.length() > static_cast<size_t>(max_length))
+ {
+ // First see if we can get lucky by removing any initial or final braces.
+ std::string::size_type begin = truncated_name.find_first_not_of("(<");
+ std::string::size_type end = truncated_name.find_last_not_of(")>.");
+ if (end - begin > static_cast<size_t>(max_length))
+ {
+ // We're still too long. Since this is a dotted component, use everything after the last
+ // dot, up to a maximum of |length| characters.
+ std::string::size_type last_dot = truncated_name.find_last_of(".");
+ if (last_dot != std::string::npos)
+ begin = last_dot + 1;
+
+ end = std::min(end, begin + max_length);
+ }
+
+ std::string::size_type count = end - begin + 1;
+ truncated_name = truncated_name.substr(begin, count);
+ }
+
+ SetName(truncated_name.c_str());
+}
diff --git a/source/Host/common/ThreadLauncher.cpp b/source/Host/common/ThreadLauncher.cpp
new file mode 100644
index 000000000000..ec7da325bf92
--- /dev/null
+++ b/source/Host/common/ThreadLauncher.cpp
@@ -0,0 +1,74 @@
+//===-- ThreadLauncher.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// lldb Includes
+#include "lldb/Core/Log.h"
+#include "lldb/Host/HostNativeThread.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/ThisThread.h"
+#include "lldb/Host/ThreadLauncher.h"
+
+#if defined(_WIN32)
+#include "lldb/Host/windows/windows.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostThread
+ThreadLauncher::LaunchThread(llvm::StringRef name, lldb::thread_func_t thread_function, lldb::thread_arg_t thread_arg, Error *error_ptr, size_t min_stack_byte_size)
+{
+ Error error;
+ if (error_ptr)
+ error_ptr->Clear();
+
+ // Host::ThreadCreateTrampoline will delete this pointer for us.
+ HostThreadCreateInfo *info_ptr = new HostThreadCreateInfo(name.data(), thread_function, thread_arg);
+ lldb::thread_t thread;
+#ifdef _WIN32
+ thread =
+ (lldb::thread_t)::_beginthreadex(0, (unsigned)min_stack_byte_size, HostNativeThread::ThreadCreateTrampoline, info_ptr, 0, NULL);
+ if (thread == (lldb::thread_t)(-1L))
+ error.SetError(::GetLastError(), eErrorTypeWin32);
+#else
+
+ pthread_attr_t *thread_attr_ptr = NULL;
+ pthread_attr_t thread_attr;
+ bool destroy_attr = false;
+ if (min_stack_byte_size > 0)
+ {
+ if (::pthread_attr_init (&thread_attr) == 0)
+ {
+ destroy_attr = true;
+ size_t default_min_stack_byte_size = 0;
+ if (::pthread_attr_getstacksize(&thread_attr, &default_min_stack_byte_size) == 0)
+ {
+ if (default_min_stack_byte_size < min_stack_byte_size)
+ {
+ if (::pthread_attr_setstacksize (&thread_attr, min_stack_byte_size) == 0)
+ thread_attr_ptr = &thread_attr;
+ }
+ }
+
+ }
+ }
+ int err = ::pthread_create(&thread, thread_attr_ptr, HostNativeThread::ThreadCreateTrampoline, info_ptr);
+
+ if (destroy_attr)
+ ::pthread_attr_destroy(&thread_attr);
+
+ error.SetError(err, eErrorTypePOSIX);
+#endif
+ if (error_ptr)
+ *error_ptr = error;
+ if (!error.Success())
+ thread = LLDB_INVALID_HOST_THREAD;
+
+ return HostThread(thread);
+}
diff --git a/source/Host/freebsd/Host.cpp b/source/Host/freebsd/Host.cpp
index dc092e86d78b..2cbf4d8f4696 100644
--- a/source/Host/freebsd/Host.cpp
+++ b/source/Host/freebsd/Host.cpp
@@ -50,80 +50,6 @@ extern "C" {
using namespace lldb;
using namespace lldb_private;
-class FreeBSDThread
-{
-public:
- FreeBSDThread(const char *thread_name)
- {
- Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name);
- }
- static void PThreadDestructor (void *v)
- {
- delete (FreeBSDThread*)v;
- }
-};
-
-static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
-static pthread_key_t g_thread_create_key = 0;
-
-static void
-InitThreadCreated()
-{
- ::pthread_key_create (&g_thread_create_key, FreeBSDThread::PThreadDestructor);
-}
-
-void
-Host::ThreadCreated (const char *thread_name)
-{
- ::pthread_once (&g_thread_create_once, InitThreadCreated);
- if (g_thread_create_key)
- {
- ::pthread_setspecific (g_thread_create_key, new FreeBSDThread(thread_name));
- }
-
- Host::SetShortThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name, 16);
-}
-
-std::string
-Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid)
-{
- struct kinfo_proc *kp = nullptr, *nkp;
- size_t len = 0;
- int error;
- int name[4] = {
- CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, (int)pid
- };
-
- while (1) {
- error = sysctl(name, 4, kp, &len, nullptr, 0);
- if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
- // Add extra space in case threads are added before next call.
- len += sizeof(*kp) + len / 10;
- nkp = (struct kinfo_proc *)realloc(kp, len);
- if (nkp == nullptr)
- {
- free(kp);
- return std::string();
- }
- kp = nkp;
- continue;
- }
- if (error != 0)
- len = 0;
- break;
- }
-
- std::string thread_name;
- for (size_t i = 0; i < len / sizeof(*kp); i++) {
- if (kp[i].ki_tid == (int)tid) {
- thread_name = kp[i].ki_tdname;
- break;
- }
- }
- free(kp);
- return thread_name;
-}
-
void
Host::Backtrace (Stream &strm, uint32_t max_frames)
{
@@ -363,43 +289,19 @@ Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
lldb::DataBufferSP
Host::GetAuxvData(lldb_private::Process *process)
{
- int mib[2] = { CTL_KERN, KERN_PS_STRINGS };
- void *ps_strings_addr, *auxv_addr;
- size_t ps_strings_size = sizeof(void *);
- Elf_Auxinfo aux_info[AT_COUNT];
- struct ps_strings ps_strings;
- struct ptrace_io_desc pid;
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_AUXV, 0 };
+ size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo);
DataBufferSP buf_sp;
- std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
-
- if (::sysctl(mib, 2, &ps_strings_addr, &ps_strings_size, NULL, 0) == 0) {
- pid.piod_op = PIOD_READ_D;
- pid.piod_addr = &ps_strings;
- pid.piod_offs = ps_strings_addr;
- pid.piod_len = sizeof(ps_strings);
- if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
- perror("failed to fetch ps_strings");
- buf_ap.release();
- goto done;
- }
-
- auxv_addr = ps_strings.ps_envstr + ps_strings.ps_nenvstr + 1;
-
- pid.piod_addr = aux_info;
- pid.piod_offs = auxv_addr;
- pid.piod_len = sizeof(aux_info);
- if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
- perror("failed to fetch aux_info");
- buf_ap.release();
- goto done;
- }
- memcpy(buf_ap->GetBytes(), aux_info, pid.piod_len);
+
+ std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(auxv_size, 0));
+
+ mib[3] = process->GetID();
+ if (::sysctl(mib, 4, buf_ap->GetBytes(), &auxv_size, NULL, 0) == 0) {
buf_sp.reset(buf_ap.release());
} else {
- perror("sysctl failed on ps_strings");
+ perror("sysctl failed on auxv");
}
- done:
return buf_sp;
}
diff --git a/source/Host/freebsd/HostInfoFreeBSD.cpp b/source/Host/freebsd/HostInfoFreeBSD.cpp
index 78458259f0a2..d51109320c3b 100644
--- a/source/Host/freebsd/HostInfoFreeBSD.cpp
+++ b/source/Host/freebsd/HostInfoFreeBSD.cpp
@@ -17,6 +17,12 @@
using namespace lldb_private;
+uint32_t
+HostInfoFreeBSD::GetMaxThreadNameLength()
+{
+ return 16;
+}
+
bool
HostInfoFreeBSD::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update)
{
diff --git a/source/Host/freebsd/HostThreadFreeBSD.cpp b/source/Host/freebsd/HostThreadFreeBSD.cpp
new file mode 100644
index 000000000000..7d611bb6894b
--- /dev/null
+++ b/source/Host/freebsd/HostThreadFreeBSD.cpp
@@ -0,0 +1,77 @@
+//===-- HostThreadFreeBSD.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// lldb Includes
+#include "lldb/Host/freebsd/HostThreadFreeBSD.h"
+#include "lldb/Host/Host.h"
+
+// C includes
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <stdlib.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+// C++ includes
+#include <string>
+
+using namespace lldb_private;
+
+HostThreadFreeBSD::HostThreadFreeBSD()
+{
+}
+
+HostThreadFreeBSD::HostThreadFreeBSD(lldb::thread_t thread)
+ : HostThreadPosix(thread)
+{
+}
+
+void
+HostThreadFreeBSD::GetName(lldb::tid_t tid, llvm::SmallVectorImpl<char> &name)
+{
+ name.clear();
+ int pid = Host::GetCurrentProcessID();
+
+ struct kinfo_proc *kp = nullptr, *nkp;
+ size_t len = 0;
+ int error;
+ int ctl[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, (int)pid};
+
+ while (1)
+ {
+ error = sysctl(ctl, 4, kp, &len, nullptr, 0);
+ if (kp == nullptr || (error != 0 && errno == ENOMEM))
+ {
+ // Add extra space in case threads are added before next call.
+ len += sizeof(*kp) + len / 10;
+ nkp = (struct kinfo_proc *)realloc(kp, len);
+ if (nkp == nullptr)
+ {
+ free(kp);
+ return;
+ }
+ kp = nkp;
+ continue;
+ }
+ if (error != 0)
+ len = 0;
+ break;
+ }
+
+ for (size_t i = 0; i < len / sizeof(*kp); i++)
+ {
+ if (kp[i].ki_tid == (lwpid_t)tid)
+ {
+ name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname));
+ break;
+ }
+ }
+ free(kp);
+}
diff --git a/source/Host/freebsd/ThisThread.cpp b/source/Host/freebsd/ThisThread.cpp
new file mode 100644
index 000000000000..fb25847be24f
--- /dev/null
+++ b/source/Host/freebsd/ThisThread.cpp
@@ -0,0 +1,30 @@
+//===-- ThisThread.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/HostNativeThread.h"
+#include "lldb/Host/ThisThread.h"
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <pthread.h>
+#include <pthread_np.h>
+
+using namespace lldb_private;
+
+void
+ThisThread::SetName(llvm::StringRef name)
+{
+ ::pthread_set_name_np(::pthread_self(), name.data());
+}
+
+void
+ThisThread::GetName(llvm::SmallVectorImpl<char> &name)
+{
+ HostNativeThread::GetName(::pthread_getthreadid_np(), name);
+}
diff --git a/source/Core/ConnectionFileDescriptor.cpp b/source/Host/posix/ConnectionFileDescriptorPosix.cpp
index 7c8e98a21129..38ddc0a49220 100644
--- a/source/Core/ConnectionFileDescriptor.cpp
+++ b/source/Host/posix/ConnectionFileDescriptorPosix.cpp
@@ -1,4 +1,4 @@
-//===-- ConnectionFileDescriptor.cpp ----------------------------*- C++ -*-===//
+//===-- ConnectionFileDescriptorPosix.cpp -----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,7 +14,7 @@
#define _DARWIN_UNLIMITED_SELECT
#endif
-#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/IOObject.h"
#include "lldb/Host/SocketAddress.h"
@@ -46,99 +46,94 @@
#include "lldb/Host/Socket.h"
#include "lldb/Interpreter/Args.h"
-
using namespace lldb;
using namespace lldb_private;
-ConnectionFileDescriptor::ConnectionFileDescriptor () :
- Connection(),
- m_pipe (),
- m_mutex (Mutex::eMutexTypeRecursive),
- m_shutting_down (false),
- m_waiting_for_accept (false)
+ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit)
+ : Connection()
+ , m_pipe()
+ , m_mutex(Mutex::eMutexTypeRecursive)
+ , m_shutting_down(false)
+ , m_waiting_for_accept(false)
+ , m_child_processes_inherit(child_processes_inherit)
{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",
- static_cast<void*>(this));
+ log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", static_cast<void *>(this));
}
-ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) :
- Connection(),
- m_pipe (),
- m_mutex (Mutex::eMutexTypeRecursive),
- m_shutting_down (false),
- m_waiting_for_accept (false)
+ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd)
+ : Connection()
+ , m_pipe()
+ , m_mutex(Mutex::eMutexTypeRecursive)
+ , m_shutting_down(false)
+ , m_waiting_for_accept(false)
+ , m_child_processes_inherit(false)
{
m_write_sp.reset(new File(fd, owns_fd));
m_read_sp.reset(new File(fd, false));
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)",
- static_cast<void*>(this), fd, owns_fd);
- OpenCommandPipe ();
+ log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", static_cast<void *>(this), fd,
+ owns_fd);
+ OpenCommandPipe();
}
-
-ConnectionFileDescriptor::~ConnectionFileDescriptor ()
+ConnectionFileDescriptor::~ConnectionFileDescriptor()
{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
- static_cast<void*>(this));
- Disconnect (NULL);
- CloseCommandPipe ();
+ log->Printf("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", static_cast<void *>(this));
+ Disconnect(NULL);
+ CloseCommandPipe();
}
void
-ConnectionFileDescriptor::OpenCommandPipe ()
+ConnectionFileDescriptor::OpenCommandPipe()
{
CloseCommandPipe();
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
// Make the command file descriptor here:
- if (!m_pipe.Open())
+ Error result = m_pipe.CreateNew(m_child_processes_inherit);
+ if (!result.Success())
{
if (log)
- log->Printf ("%p ConnectionFileDescriptor::OpenCommandPipe () - could not make pipe: %s",
- static_cast<void*>(this), strerror(errno));
+ log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not make pipe: %s", static_cast<void *>(this),
+ result.AsCString());
}
else
{
if (log)
- log->Printf ("%p ConnectionFileDescriptor::OpenCommandPipe() - success readfd=%d writefd=%d",
- static_cast<void*>(this),
- m_pipe.GetReadFileDescriptor(),
- m_pipe.GetWriteFileDescriptor());
+ log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success readfd=%d writefd=%d", static_cast<void *>(this),
+ m_pipe.GetReadFileDescriptor(), m_pipe.GetWriteFileDescriptor());
}
}
void
-ConnectionFileDescriptor::CloseCommandPipe ()
+ConnectionFileDescriptor::CloseCommandPipe()
{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::CloseCommandPipe()",
- static_cast<void*>(this));
+ log->Printf("%p ConnectionFileDescriptor::CloseCommandPipe()", static_cast<void *>(this));
m_pipe.Close();
}
bool
-ConnectionFileDescriptor::IsConnected () const
+ConnectionFileDescriptor::IsConnected() const
{
return (m_read_sp && m_read_sp->IsValid()) || (m_write_sp && m_write_sp->IsValid());
}
ConnectionStatus
-ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
+ConnectionFileDescriptor::Connect(const char *s, Error *error_ptr)
{
- Mutex::Locker locker (m_mutex);
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ Mutex::Locker locker(m_mutex);
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::Connect (url = '%s')",
- static_cast<void*>(this), s);
+ log->Printf("%p ConnectionFileDescriptor::Connect (url = '%s')", static_cast<void *>(this), s);
OpenCommandPipe();
@@ -147,54 +142,51 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
if (strstr(s, "listen://") == s)
{
// listen://HOST:PORT
- return SocketListen (s + strlen("listen://"), error_ptr);
+ return SocketListen(s + strlen("listen://"), error_ptr);
}
else if (strstr(s, "accept://") == s)
{
// unix://SOCKNAME
- return NamedSocketAccept (s + strlen("accept://"), error_ptr);
+ return NamedSocketAccept(s + strlen("accept://"), error_ptr);
}
else if (strstr(s, "unix-accept://") == s)
{
// unix://SOCKNAME
- return NamedSocketAccept (s + strlen("unix-accept://"), error_ptr);
+ return NamedSocketAccept(s + strlen("unix-accept://"), error_ptr);
}
else if (strstr(s, "connect://") == s)
{
- return ConnectTCP (s + strlen("connect://"), error_ptr);
+ return ConnectTCP(s + strlen("connect://"), error_ptr);
}
else if (strstr(s, "tcp-connect://") == s)
{
- return ConnectTCP (s + strlen("tcp-connect://"), error_ptr);
+ return ConnectTCP(s + strlen("tcp-connect://"), error_ptr);
}
else if (strstr(s, "udp://") == s)
{
- return ConnectUDP (s + strlen("udp://"), error_ptr);
+ return ConnectUDP(s + strlen("udp://"), error_ptr);
}
#ifndef LLDB_DISABLE_POSIX
else if (strstr(s, "fd://") == s)
{
- if (error_ptr)
- error_ptr->SetErrorStringWithFormat ("Protocol is not supported on non-posix hosts '%s'", s);
- return eConnectionStatusError;
// Just passing a native file descriptor within this current process
// that is already opened (possibly from a service or other source).
- s += strlen ("fd://");
+ s += strlen("fd://");
bool success = false;
- int fd = Args::StringToSInt32 (s, -1, 0, &success);
+ int fd = Args::StringToSInt32(s, -1, 0, &success);
if (success)
{
- // We have what looks to be a valid file descriptor, but we
+ // We have what looks to be a valid file descriptor, but we
// should make sure it is. We currently are doing this by trying to
- // get the flags from the file descriptor and making sure it
+ // get the flags from the file descriptor and making sure it
// isn't a bad fd.
errno = 0;
- int flags = ::fcntl (fd, F_GETFL, 0);
+ int flags = ::fcntl(fd, F_GETFL, 0);
if (flags == -1 || errno == EBADF)
{
if (error_ptr)
- error_ptr->SetErrorStringWithFormat ("stale file descriptor: %s", s);
+ error_ptr->SetErrorStringWithFormat("stale file descriptor: %s", s);
m_read_sp.reset();
m_write_sp.reset();
return eConnectionStatusError;
@@ -203,17 +195,17 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
{
// Don't take ownership of a file descriptor that gets passed
// to us since someone else opened the file descriptor and
- // handed it to us.
- // TODO: Since are using a URL to open connection we should
+ // handed it to us.
+ // TODO: Since are using a URL to open connection we should
// eventually parse options using the web standard where we
// have "fd://123?opt1=value;opt2=value" and we can have an
// option be "owns=1" or "owns=0" or something like this to
- // allow us to specify this. For now, we assume we must
+ // allow us to specify this. For now, we assume we must
// assume we don't own it.
std::unique_ptr<Socket> tcp_socket;
tcp_socket.reset(new Socket(fd, Socket::ProtocolTcp, false));
- // Try and get a socket option from this file descriptor to
+ // Try and get a socket option from this file descriptor to
// see if this is a socket and set m_is_socket accordingly.
int resuse;
bool is_socket = !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);
@@ -232,7 +224,7 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
}
if (error_ptr)
- error_ptr->SetErrorStringWithFormat ("invalid file descriptor: \"fd://%s\"", s);
+ error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"fd://%s\"", s);
m_read_sp.reset();
m_write_sp.reset();
return eConnectionStatusError;
@@ -244,7 +236,7 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
int fd = -1;
do
{
- fd = ::open (path, O_RDWR);
+ fd = ::open(path, O_RDWR);
} while (fd == -1 && errno == EINTR);
if (fd == -1)
@@ -258,29 +250,29 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
{
// Set up serial terminal emulation
struct termios options;
- ::tcgetattr (fd, &options);
+ ::tcgetattr(fd, &options);
// Set port speed to maximum
- ::cfsetospeed (&options, B115200);
- ::cfsetispeed (&options, B115200);
+ ::cfsetospeed(&options, B115200);
+ ::cfsetispeed(&options, B115200);
// Raw input, disable echo and signals
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// Make sure only one character is needed to return from a read
- options.c_cc[VMIN] = 1;
+ options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
- ::tcsetattr (fd, TCSANOW, &options);
+ ::tcsetattr(fd, TCSANOW, &options);
}
- int flags = ::fcntl (fd, F_GETFL, 0);
+ int flags = ::fcntl(fd, F_GETFL, 0);
if (flags >= 0)
{
if ((flags & O_NONBLOCK) == 0)
{
flags |= O_NONBLOCK;
- ::fcntl (fd, F_SETFL, flags);
+ ::fcntl(fd, F_SETFL, flags);
}
}
m_read_sp.reset(new File(fd, true));
@@ -289,7 +281,7 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
}
#endif
if (error_ptr)
- error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);
+ error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", s);
return eConnectionStatusError;
}
if (error_ptr)
@@ -300,29 +292,29 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
bool
ConnectionFileDescriptor::InterruptRead()
{
- return m_pipe.Write("i", 1) == 1;
+ size_t bytes_written = 0;
+ Error result = m_pipe.Write("i", 1, bytes_written);
+ return result.Success();
}
ConnectionStatus
-ConnectionFileDescriptor::Disconnect (Error *error_ptr)
+ConnectionFileDescriptor::Disconnect(Error *error_ptr)
{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::Disconnect ()",
- static_cast<void*>(this));
+ log->Printf("%p ConnectionFileDescriptor::Disconnect ()", static_cast<void *>(this));
ConnectionStatus status = eConnectionStatusSuccess;
if (!IsConnected())
{
if (log)
- log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect",
- static_cast<void*>(this));
+ log->Printf("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", static_cast<void *>(this));
return eConnectionStatusSuccess;
}
if (m_read_sp && m_read_sp->IsValid() && m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
- static_cast<Socket&>(*m_read_sp).PreDisconnect();
+ static_cast<Socket &>(*m_read_sp).PreDisconnect();
// Try to get the ConnectionFileDescriptor's mutex. If we fail, that is quite likely
// because somebody is doing a blocking read on our file descriptor. If that's the case,
@@ -332,24 +324,24 @@ ConnectionFileDescriptor::Disconnect (Error *error_ptr)
m_shutting_down = true;
Mutex::Locker locker;
- bool got_lock = locker.TryLock (m_mutex);
+ bool got_lock = locker.TryLock(m_mutex);
if (!got_lock)
{
- if (m_pipe.WriteDescriptorIsValid())
+ if (m_pipe.CanWrite())
{
- int result;
- result = m_pipe.Write("q", 1) == 1;
+ size_t bytes_written = 0;
+ Error result = m_pipe.Write("q", 1, bytes_written);
if (log)
- log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, result = %d.",
- static_cast<void*>(this), m_pipe.GetWriteFileDescriptor(), result);
+ log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, error = '%s'.",
+ static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), result.AsCString());
}
else if (log)
{
- log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.",
- static_cast<void*>(this));
+ log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.",
+ static_cast<void *>(this));
}
- locker.Lock (m_mutex);
+ locker.Lock(m_mutex);
}
Error error = m_read_sp->Close();
@@ -364,23 +356,18 @@ ConnectionFileDescriptor::Disconnect (Error *error_ptr)
}
size_t
-ConnectionFileDescriptor::Read (void *dst,
- size_t dst_len,
- uint32_t timeout_usec,
- ConnectionStatus &status,
- Error *error_ptr)
+ConnectionFileDescriptor::Read(void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr)
{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
Mutex::Locker locker;
- bool got_lock = locker.TryLock (m_mutex);
+ bool got_lock = locker.TryLock(m_mutex);
if (!got_lock)
{
if (log)
- log->Printf ("%p ConnectionFileDescriptor::Read () failed to get the connection lock.",
- static_cast<void*>(this));
+ log->Printf("%p ConnectionFileDescriptor::Read () failed to get the connection lock.", static_cast<void *>(this));
if (error_ptr)
- error_ptr->SetErrorString ("failed to get the connection lock for read.");
+ error_ptr->SetErrorString("failed to get the connection lock for read.");
status = eConnectionStatusTimedOut;
return 0;
@@ -388,7 +375,7 @@ ConnectionFileDescriptor::Read (void *dst,
else if (m_shutting_down)
return eConnectionStatusError;
- status = BytesAvailable (timeout_usec, error_ptr);
+ status = BytesAvailable(timeout_usec, error_ptr);
if (status != eConnectionStatusSuccess)
return 0;
@@ -399,12 +386,8 @@ ConnectionFileDescriptor::Read (void *dst,
if (log)
{
log->Printf("%p ConnectionFileDescriptor::Read() fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s",
- static_cast<void*>(this),
- static_cast<uint64_t>(m_read_sp->GetWaitableHandle()),
- static_cast<void*>(dst),
- static_cast<uint64_t>(dst_len),
- static_cast<uint64_t>(bytes_read),
- error.AsCString());
+ static_cast<void *>(this), static_cast<uint64_t>(m_read_sp->GetWaitableHandle()), static_cast<void *>(dst),
+ static_cast<uint64_t>(dst_len), static_cast<uint64_t>(bytes_read), error.AsCString());
}
if (bytes_read == 0)
@@ -421,49 +404,48 @@ ConnectionFileDescriptor::Read (void *dst,
uint32_t error_value = error.GetError();
switch (error_value)
{
- case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read.
- if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
+ case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read.
+ if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
+ status = eConnectionStatusTimedOut;
+ else
+ status = eConnectionStatusSuccess;
+ return 0;
+
+ case EFAULT: // Buf points outside the allocated address space.
+ case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal.
+ case EINVAL: // The pointer associated with fildes was negative.
+ case EIO: // An I/O error occurred while reading from the file system.
+ // The process group is orphaned.
+ // The file is a regular file, nbyte is greater than 0,
+ // the starting position is before the end-of-file, and
+ // the starting position is greater than or equal to the
+ // offset maximum established for the open file
+ // descriptor associated with fildes.
+ case EISDIR: // An attempt is made to read a directory.
+ case ENOBUFS: // An attempt to allocate a memory buffer fails.
+ case ENOMEM: // Insufficient memory is available.
+ status = eConnectionStatusError;
+ break; // Break to close....
+
+ case ENOENT: // no such file or directory
+ case EBADF: // fildes is not a valid file or socket descriptor open for reading.
+ case ENXIO: // An action is requested of a device that does not exist..
+ // A requested action cannot be performed by the device.
+ case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket.
+ case ENOTCONN: // A read is attempted on an unconnected socket.
+ status = eConnectionStatusLostConnection;
+ break; // Break to close....
+
+ case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket.
status = eConnectionStatusTimedOut;
- else
- status = eConnectionStatusSuccess;
- return 0;
-
- case EFAULT: // Buf points outside the allocated address space.
- case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal.
- case EINVAL: // The pointer associated with fildes was negative.
- case EIO: // An I/O error occurred while reading from the file system.
- // The process group is orphaned.
- // The file is a regular file, nbyte is greater than 0,
- // the starting position is before the end-of-file, and
- // the starting position is greater than or equal to the
- // offset maximum established for the open file
- // descriptor associated with fildes.
- case EISDIR: // An attempt is made to read a directory.
- case ENOBUFS: // An attempt to allocate a memory buffer fails.
- case ENOMEM: // Insufficient memory is available.
- status = eConnectionStatusError;
- break; // Break to close....
-
- case ENOENT: // no such file or directory
- case EBADF: // fildes is not a valid file or socket descriptor open for reading.
- case ENXIO: // An action is requested of a device that does not exist..
- // A requested action cannot be performed by the device.
- case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket.
- case ENOTCONN: // A read is attempted on an unconnected socket.
- status = eConnectionStatusLostConnection;
- break; // Break to close....
-
- case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket.
- status = eConnectionStatusTimedOut;
- return 0;
-
- default:
- if (log)
- log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s",
- static_cast<void*>(this), strerror(error_value));
- status = eConnectionStatusError;
- break; // Break to close....
-
+ return 0;
+
+ default:
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s", static_cast<void *>(this),
+ strerror(error_value));
+ status = eConnectionStatusError;
+ break; // Break to close....
}
return 0;
@@ -472,15 +454,14 @@ ConnectionFileDescriptor::Read (void *dst,
}
size_t
-ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
+ConnectionFileDescriptor::Write(const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")",
- static_cast<void*>(this), static_cast<const void*>(src),
- static_cast<uint64_t>(src_len));
+ log->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", static_cast<void *>(this),
+ static_cast<const void *>(src), static_cast<uint64_t>(src_len));
- if (!IsConnected ())
+ if (!IsConnected())
{
if (error_ptr)
error_ptr->SetErrorString("not connected");
@@ -488,7 +469,6 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
return 0;
}
-
Error error;
size_t bytes_sent = src_len;
@@ -496,13 +476,9 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
if (log)
{
- log->Printf ("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)",
- static_cast<void*>(this),
- static_cast<uint64_t>(m_write_sp->GetWaitableHandle()),
- static_cast<const void*>(src),
- static_cast<uint64_t>(src_len),
- static_cast<uint64_t>(bytes_sent),
- error.AsCString());
+ log->Printf("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)",
+ static_cast<void *>(this), static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), static_cast<const void *>(src),
+ static_cast<uint64_t>(src_len), static_cast<uint64_t>(bytes_sent), error.AsCString());
}
if (error_ptr)
@@ -512,19 +488,19 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
{
switch (error.GetError())
{
- case EAGAIN:
- case EINTR:
- status = eConnectionStatusSuccess;
- return 0;
-
- case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket.
- case ENOTCONN: // A read is attempted on an unconnected socket.
- status = eConnectionStatusLostConnection;
- break; // Break to close....
-
- default:
- status = eConnectionStatusError;
- break; // Break to close....
+ case EAGAIN:
+ case EINTR:
+ status = eConnectionStatusSuccess;
+ return 0;
+
+ case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket.
+ case ENOTCONN: // A read is attempted on an unconnected socket.
+ status = eConnectionStatusLostConnection;
+ break; // Break to close....
+
+ default:
+ status = eConnectionStatusError;
+ break; // Break to close....
}
return 0;
@@ -534,8 +510,6 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
return bytes_sent;
}
-
-
// This ConnectionFileDescriptor::BytesAvailable() uses select().
//
// PROS:
@@ -557,15 +531,14 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
#endif
ConnectionStatus
-ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+ConnectionFileDescriptor::BytesAvailable(uint32_t timeout_usec, Error *error_ptr)
{
// Don't need to take the mutex here separately since we are only called from Read. If we
// ever get used more generally we will need to lock here as well.
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)",
- static_cast<void*>(this), timeout_usec);
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", static_cast<void *>(this), timeout_usec);
struct timeval *tv_ptr;
struct timeval tv;
@@ -577,7 +550,7 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
else
{
TimeValue time_value;
- time_value.OffsetWithMicroSeconds (timeout_usec);
+ time_value.OffsetWithMicroSeconds(timeout_usec);
tv.tv_sec = time_value.seconds();
tv.tv_usec = time_value.microseconds();
tv_ptr = &tv;
@@ -599,9 +572,9 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
#else
const bool have_pipe_fd = pipe_fd >= 0;
#if !defined(__APPLE__)
- assert (handle < FD_SETSIZE);
+ assert(handle < FD_SETSIZE);
if (have_pipe_fd)
- assert (pipe_fd < FD_SETSIZE);
+ assert(pipe_fd < FD_SETSIZE);
#endif
#endif
while (handle == m_read_sp->GetWaitableHandle())
@@ -609,35 +582,34 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
const int nfds = std::max<int>(handle, pipe_fd) + 1;
#if defined(__APPLE__)
llvm::SmallVector<fd_set, 1> read_fds;
- read_fds.resize((nfds/FD_SETSIZE) + 1);
- for (size_t i=0; i<read_fds.size(); ++i)
- FD_ZERO (&read_fds[i]);
- // FD_SET doesn't bounds check, it just happily walks off the end
- // but we have taken care of making the extra storage with our
- // SmallVector of fd_set objects
+ read_fds.resize((nfds / FD_SETSIZE) + 1);
+ for (size_t i = 0; i < read_fds.size(); ++i)
+ FD_ZERO(&read_fds[i]);
+// FD_SET doesn't bounds check, it just happily walks off the end
+// but we have taken care of making the extra storage with our
+// SmallVector of fd_set objects
#else
fd_set read_fds;
- FD_ZERO (&read_fds);
+ FD_ZERO(&read_fds);
#endif
- FD_SET (handle, FD_SET_DATA(read_fds));
+ FD_SET(handle, FD_SET_DATA(read_fds));
if (have_pipe_fd)
- FD_SET (pipe_fd, FD_SET_DATA(read_fds));
+ FD_SET(pipe_fd, FD_SET_DATA(read_fds));
Error error;
if (log)
{
if (have_pipe_fd)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
- static_cast<void*>(this), nfds, handle, pipe_fd,
- static_cast<void*>(tv_ptr));
+ log->Printf(
+ "%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
+ static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr));
else
log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
- static_cast<void*>(this), nfds, handle,
- static_cast<void*>(tv_ptr));
+ static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr));
}
- const int num_set_fds = ::select (nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr);
+ const int num_set_fds = ::select(nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr);
if (num_set_fds < 0)
error.SetErrorToErrno();
else
@@ -646,15 +618,14 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
if (log)
{
if (have_pipe_fd)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s",
- static_cast<void*>(this), nfds, handle,
- pipe_fd, static_cast<void*>(tv_ptr), num_set_fds,
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) "
+ "=> %d, error = %s",
+ static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr), num_set_fds,
error.AsCString());
else
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s",
- static_cast<void*>(this), nfds, handle,
- static_cast<void*>(tv_ptr), num_set_fds,
- error.AsCString());
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => "
+ "%d, error = %s",
+ static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr), num_set_fds, error.AsCString());
}
if (error_ptr)
@@ -664,20 +635,20 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
{
switch (error.GetError())
{
- case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
return eConnectionStatusLostConnection;
- case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
- default: // Other unknown error
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
return eConnectionStatusError;
- case EAGAIN: // The kernel was (perhaps temporarily) unable to
- // allocate the requested number of file descriptors,
- // or we have non-blocking IO
- case EINTR: // A signal was delivered before the time limit
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to
+ // allocate the requested number of file descriptors,
+ // or we have non-blocking IO
+ case EINTR: // A signal was delivered before the time limit
// expired and before any of the selected events
// occurred.
- break; // Lets keep reading to until we timeout
+ break; // Lets keep reading to until we timeout
}
}
else if (num_set_fds == 0)
@@ -696,20 +667,19 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
do
{
- bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
+ bytes_read = ::read(pipe_fd, buffer, sizeof(buffer));
} while (bytes_read < 0 && errno == EINTR);
-
+
switch (buffer[0])
{
- case 'q':
- if (log)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
- static_cast<void*>(this),
- static_cast<int>(bytes_read), buffer);
- return eConnectionStatusEndOfFile;
- case 'i':
- // Interrupt the current read
- return eConnectionStatusInterrupted;
+ case 'q':
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
+ static_cast<void *>(this), static_cast<int>(bytes_read), buffer);
+ return eConnectionStatusEndOfFile;
+ case 'i':
+ // Interrupt the current read
+ return eConnectionStatusInterrupted;
}
}
}
@@ -722,10 +692,10 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
}
ConnectionStatus
-ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *error_ptr)
+ConnectionFileDescriptor::NamedSocketAccept(const char *socket_name, Error *error_ptr)
{
- Socket* socket = nullptr;
- Error error = Socket::UnixDomainAccept(socket_name, socket);
+ Socket *socket = nullptr;
+ Error error = Socket::UnixDomainAccept(socket_name, m_child_processes_inherit, socket);
if (error_ptr)
*error_ptr = error;
m_write_sp.reset(socket);
@@ -734,10 +704,10 @@ ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *err
}
ConnectionStatus
-ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *error_ptr)
+ConnectionFileDescriptor::NamedSocketConnect(const char *socket_name, Error *error_ptr)
{
- Socket* socket = nullptr;
- Error error = Socket::UnixDomainConnect(socket_name, socket);
+ Socket *socket = nullptr;
+ Error error = Socket::UnixDomainConnect(socket_name, m_child_processes_inherit, socket);
if (error_ptr)
*error_ptr = error;
m_write_sp.reset(socket);
@@ -750,9 +720,9 @@ ConnectionFileDescriptor::SocketListen(const char *s, Error *error_ptr)
{
m_port_predicate.SetValue(0, eBroadcastNever);
- Socket* socket = nullptr;
+ Socket *socket = nullptr;
m_waiting_for_accept = true;
- Error error = Socket::TcpListen(s, socket, &m_port_predicate);
+ Error error = Socket::TcpListen(s, m_child_processes_inherit, socket, &m_port_predicate);
if (error_ptr)
*error_ptr = error;
if (error.Fail())
@@ -762,7 +732,7 @@ ConnectionFileDescriptor::SocketListen(const char *s, Error *error_ptr)
listening_socket_up.reset(socket);
socket = nullptr;
- error = listening_socket_up->BlockingAccept(s, socket);
+ error = listening_socket_up->BlockingAccept(s, m_child_processes_inherit, socket);
listening_socket_up.reset();
if (error_ptr)
*error_ptr = error;
@@ -777,8 +747,8 @@ ConnectionFileDescriptor::SocketListen(const char *s, Error *error_ptr)
ConnectionStatus
ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr)
{
- Socket* socket = nullptr;
- Error error = Socket::TcpConnect(s, socket);
+ Socket *socket = nullptr;
+ Error error = Socket::TcpConnect(s, m_child_processes_inherit, socket);
if (error_ptr)
*error_ptr = error;
m_write_sp.reset(socket);
@@ -789,9 +759,9 @@ ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr)
ConnectionStatus
ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr)
{
- Socket* send_socket = nullptr;
- Socket* recv_socket = nullptr;
- Error error = Socket::UdpConnect(s, send_socket, recv_socket);
+ Socket *send_socket = nullptr;
+ Socket *recv_socket = nullptr;
+ Error error = Socket::UdpConnect(s, m_child_processes_inherit, send_socket, recv_socket);
if (error_ptr)
*error_ptr = error;
m_write_sp.reset(send_socket);
@@ -799,17 +769,29 @@ ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr)
return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError;
}
-
-uint16_t ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec)
+uint16_t
+ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec)
{
uint16_t bound_port = 0;
if (timeout_sec == UINT32_MAX)
- m_port_predicate.WaitForValueNotEqualTo (0, bound_port);
+ m_port_predicate.WaitForValueNotEqualTo(0, bound_port);
else
{
TimeValue timeout = TimeValue::Now();
timeout.OffsetWithSeconds(timeout_sec);
- m_port_predicate.WaitForValueNotEqualTo (0, bound_port, &timeout);
+ m_port_predicate.WaitForValueNotEqualTo(0, bound_port, &timeout);
}
return bound_port;
}
+
+bool
+ConnectionFileDescriptor::GetChildProcessesInherit() const
+{
+ return m_child_processes_inherit;
+}
+
+void
+ConnectionFileDescriptor::SetChildProcessesInherit(bool child_processes_inherit)
+{
+ m_child_processes_inherit = child_processes_inherit;
+}
diff --git a/source/Host/posix/HostInfoPosix.cpp b/source/Host/posix/HostInfoPosix.cpp
index 77fdc2b61a31..018d423ee9d3 100644
--- a/source/Host/posix/HostInfoPosix.cpp
+++ b/source/Host/posix/HostInfoPosix.cpp
@@ -69,6 +69,7 @@ HostInfoPosix::LookupUserName(uint32_t uid, std::string &user_name)
const char *
HostInfoPosix::LookupGroupName(uint32_t gid, std::string &group_name)
{
+#ifndef __ANDROID__
char group_buffer[PATH_MAX];
size_t group_buffer_size = sizeof(group_buffer);
struct group group_info;
@@ -94,6 +95,9 @@ HostInfoPosix::LookupGroupName(uint32_t gid, std::string &group_name)
}
}
group_name.clear();
+#else
+ assert(false && "getgrgid_r() not supported on Android");
+#endif
return NULL;
}
@@ -121,6 +125,12 @@ HostInfoPosix::GetEffectiveGroupID()
return getegid();
}
+FileSpec
+HostInfoPosix::GetDefaultShell()
+{
+ return FileSpec("/bin/sh", false);
+}
+
bool
HostInfoPosix::ComputeSupportExeDirectory(FileSpec &file_spec)
{
@@ -173,6 +183,7 @@ HostInfoPosix::ComputeHeaderDirectory(FileSpec &file_spec)
bool
HostInfoPosix::ComputePythonDirectory(FileSpec &file_spec)
{
+#ifndef LLDB_DISABLE_PYTHON
FileSpec lldb_file_spec;
if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
return false;
@@ -190,4 +201,7 @@ HostInfoPosix::ComputePythonDirectory(FileSpec &file_spec)
file_spec.GetDirectory().SetCString(raw_path);
return true;
+#else
+ return false;
+#endif
}
diff --git a/source/Host/posix/HostProcessPosix.cpp b/source/Host/posix/HostProcessPosix.cpp
index 4618de4711de..8e19add048ee 100644
--- a/source/Host/posix/HostProcessPosix.cpp
+++ b/source/Host/posix/HostProcessPosix.cpp
@@ -1,4 +1,4 @@
-//===-- HostProcessWindows.cpp ----------------------------------*- C++ -*-===//
+//===-- HostProcessPosix.cpp ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "lldb/Host/Host.h"
#include "lldb/Host/posix/HostProcessPosix.h"
#include "lldb/Host/FileSystem.h"
@@ -16,49 +17,52 @@
using namespace lldb_private;
-const lldb::pid_t HostProcessPosix::kInvalidProcessId = 0;
+namespace
+{
+ const int kInvalidPosixProcess = 0;
+}
HostProcessPosix::HostProcessPosix()
-: m_pid(kInvalidProcessId)
+ : HostNativeProcessBase(kInvalidPosixProcess)
{
}
-HostProcessPosix::~HostProcessPosix()
+HostProcessPosix::HostProcessPosix(lldb::process_t process)
+ : HostNativeProcessBase(process)
{
}
-Error HostProcessPosix::Create(lldb::pid_t pid)
+HostProcessPosix::~HostProcessPosix()
{
- Error error;
- if (pid == kInvalidProcessId)
- error.SetErrorString("Attempt to create an invalid process");
-
- m_pid = pid;
- return error;
}
Error HostProcessPosix::Signal(int signo) const
{
- if (m_pid <= 0)
+ if (m_process == kInvalidPosixProcess)
{
Error error;
error.SetErrorString("HostProcessPosix refers to an invalid process");
return error;
}
- return HostProcessPosix::Signal(m_pid, signo);
+ return HostProcessPosix::Signal(m_process, signo);
}
-Error HostProcessPosix::Signal(lldb::pid_t pid, int signo)
+Error HostProcessPosix::Signal(lldb::process_t process, int signo)
{
Error error;
- if (-1 == ::kill(pid, signo))
+ if (-1 == ::kill(process, signo))
error.SetErrorToErrno();
return error;
}
+Error HostProcessPosix::Terminate()
+{
+ return Signal(SIGKILL);
+}
+
Error HostProcessPosix::GetMainModule(FileSpec &file_spec) const
{
Error error;
@@ -66,7 +70,7 @@ 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_pid) <= 0)
+ if (snprintf (link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", m_process) <= 0)
{
error.SetErrorString("Unable to build /proc/<pid>/exe string");
return error;
@@ -92,12 +96,21 @@ Error HostProcessPosix::GetMainModule(FileSpec &file_spec) const
lldb::pid_t HostProcessPosix::GetProcessId() const
{
- return m_pid;
+ return m_process;
}
bool HostProcessPosix::IsRunning() const
{
+ if (m_process == kInvalidPosixProcess)
+ return false;
+
// Send this process the null signal. If it succeeds the process is running.
Error error = Signal(0);
return error.Success();
}
+
+HostThread
+HostProcessPosix::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals)
+{
+ return Host::StartMonitoringChildProcess(callback, callback_baton, m_process, monitor_signals);
+}
diff --git a/source/Host/posix/HostThreadPosix.cpp b/source/Host/posix/HostThreadPosix.cpp
new file mode 100644
index 000000000000..9c4892431938
--- /dev/null
+++ b/source/Host/posix/HostThreadPosix.cpp
@@ -0,0 +1,74 @@
+//===-- HostThreadPosix.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/posix/HostThreadPosix.h"
+
+#include <errno.h>
+#include <pthread.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostThreadPosix::HostThreadPosix()
+{
+}
+
+HostThreadPosix::HostThreadPosix(lldb::thread_t thread)
+ : HostNativeThreadBase(thread)
+{
+}
+
+HostThreadPosix::~HostThreadPosix()
+{
+}
+
+Error
+HostThreadPosix::Join(lldb::thread_result_t *result)
+{
+ Error error;
+ if (IsJoinable())
+ {
+ int err = ::pthread_join(m_thread, result);
+ error.SetError(err, lldb::eErrorTypePOSIX);
+ }
+ else
+ {
+ if (result)
+ *result = NULL;
+ error.SetError(EINVAL, eErrorTypePOSIX);
+ }
+
+ Reset();
+ return error;
+}
+
+Error
+HostThreadPosix::Cancel()
+{
+ Error error;
+#ifndef __ANDROID__
+ int err = ::pthread_cancel(m_thread);
+ error.SetError(err, eErrorTypePOSIX);
+#else
+ error.SetErrorString("HostThreadPosix::Cancel() not supported on Android");
+#endif
+
+ return error;
+}
+
+Error
+HostThreadPosix::Detach()
+{
+ Error error;
+ int err = ::pthread_detach(m_thread);
+ error.SetError(err, eErrorTypePOSIX);
+ Reset();
+ return error;
+}
diff --git a/source/Host/posix/PipePosix.cpp b/source/Host/posix/PipePosix.cpp
new file mode 100644
index 000000000000..02838ec5124e
--- /dev/null
+++ b/source/Host/posix/PipePosix.cpp
@@ -0,0 +1,378 @@
+//===-- PipePosix.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/PipePosix.h"
+#include "lldb/Host/FileSystem.h"
+
+#include <functional>
+#include <thread>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+int PipePosix::kInvalidDescriptor = -1;
+
+enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
+
+// pipe2 is supported by Linux, FreeBSD v10 and higher.
+// TODO: Add more platforms that support pipe2.
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10)
+#define PIPE2_SUPPORTED 1
+#else
+#define PIPE2_SUPPORTED 0
+#endif
+
+namespace
+{
+
+constexpr auto OPEN_WRITER_SLEEP_TIMEOUT_MSECS = 100;
+
+#if defined(FD_CLOEXEC) && !PIPE2_SUPPORTED
+bool SetCloexecFlag(int fd)
+{
+ int flags = ::fcntl(fd, F_GETFD);
+ if (flags == -1)
+ return false;
+ return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0);
+}
+#endif
+
+std::chrono::time_point<std::chrono::steady_clock>
+Now()
+{
+ return std::chrono::steady_clock::now();
+}
+
+Error
+SelectIO(int handle, bool is_read, const std::function<Error(bool&)> &io_handler, const std::chrono::microseconds &timeout)
+{
+ Error error;
+ fd_set fds;
+ bool done = false;
+
+ using namespace std::chrono;
+
+ const auto finish_time = Now() + timeout;
+
+ while (!done)
+ {
+ struct timeval tv = {0, 0};
+ if (timeout != microseconds::zero())
+ {
+ const auto remaining_dur = duration_cast<microseconds>(finish_time - Now());
+ if (remaining_dur.count() <= 0)
+ {
+ error.SetErrorString("timeout exceeded");
+ break;
+ }
+ const auto dur_secs = duration_cast<seconds>(remaining_dur);
+ const auto dur_usecs = remaining_dur % seconds(1);
+
+ tv.tv_sec = dur_secs.count();
+ tv.tv_usec = dur_usecs.count();
+ }
+ else
+ tv.tv_sec = 1;
+
+ FD_ZERO(&fds);
+ FD_SET(handle, &fds);
+
+ const auto retval = ::select(handle + 1,
+ (is_read) ? &fds : nullptr,
+ (is_read) ? nullptr : &fds,
+ nullptr, &tv);
+ if (retval == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ error.SetErrorToErrno();
+ break;
+ }
+ if (retval == 0)
+ {
+ error.SetErrorString("timeout exceeded");
+ break;
+ }
+ if (!FD_ISSET(handle, &fds))
+ {
+ error.SetErrorString("invalid state");
+ break;
+ }
+
+ error = io_handler(done);
+ if (error.Fail())
+ {
+ if (error.GetError() == EINTR)
+ continue;
+ break;
+ }
+ }
+ return error;
+}
+
+}
+
+PipePosix::PipePosix()
+{
+ m_fds[READ] = PipePosix::kInvalidDescriptor;
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+}
+
+PipePosix::~PipePosix()
+{
+ Close();
+}
+
+Error
+PipePosix::CreateNew(bool child_processes_inherit)
+{
+ if (CanRead() || CanWrite())
+ return Error(EINVAL, eErrorTypePOSIX);
+
+ Error error;
+#if PIPE2_SUPPORTED
+ if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
+ return error;
+#else
+ if (::pipe(m_fds) == 0)
+ {
+#ifdef FD_CLOEXEC
+ if (!child_processes_inherit)
+ {
+ if (!SetCloexecFlag(m_fds[0]) || !SetCloexecFlag(m_fds[1]))
+ {
+ error.SetErrorToErrno();
+ Close();
+ return error;
+ }
+ }
+#endif
+ return error;
+ }
+#endif
+
+ error.SetErrorToErrno();
+ m_fds[READ] = PipePosix::kInvalidDescriptor;
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ return error;
+}
+
+Error
+PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit)
+{
+ if (CanRead() || CanWrite())
+ return Error("Pipe is already opened");
+
+ Error error;
+ if (::mkfifo(name.data(), 0660) != 0)
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error
+PipePosix::OpenAsReader(llvm::StringRef name, bool child_process_inherit)
+{
+ if (CanRead() || CanWrite())
+ return Error("Pipe is already opened");
+
+ int flags = O_RDONLY | O_NONBLOCK;
+ if (!child_process_inherit)
+ flags |= O_CLOEXEC;
+
+ Error error;
+ int fd = ::open(name.data(), flags);
+ if (fd != -1)
+ m_fds[READ] = fd;
+ else
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error
+PipePosix::OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, const std::chrono::microseconds &timeout)
+{
+ if (CanRead() || CanWrite())
+ return Error("Pipe is already opened");
+
+ int flags = O_WRONLY | O_NONBLOCK;
+ if (!child_process_inherit)
+ flags |= O_CLOEXEC;
+
+ using namespace std::chrono;
+ const auto finish_time = Now() + timeout;
+
+ while (!CanWrite())
+ {
+ if (timeout != microseconds::zero())
+ {
+ const auto dur = duration_cast<microseconds>(finish_time - Now()).count();
+ if (dur <= 0)
+ return Error("timeout exceeded - reader hasn't opened so far");
+ }
+
+ errno = 0;
+ int fd = ::open(name.data(), flags);
+ if (fd == -1)
+ {
+ const auto errno_copy = errno;
+ // We may get ENXIO if a reader side of the pipe hasn't opened yet.
+ if (errno_copy != ENXIO)
+ return Error(errno_copy, eErrorTypePOSIX);
+
+ std::this_thread::sleep_for(milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS));
+ }
+ else
+ {
+ m_fds[WRITE] = fd;
+ }
+ }
+
+ return Error();
+}
+
+int
+PipePosix::GetReadFileDescriptor() const
+{
+ return m_fds[READ];
+}
+
+int
+PipePosix::GetWriteFileDescriptor() const
+{
+ return m_fds[WRITE];
+}
+
+int
+PipePosix::ReleaseReadFileDescriptor()
+{
+ const int fd = m_fds[READ];
+ m_fds[READ] = PipePosix::kInvalidDescriptor;
+ return fd;
+}
+
+int
+PipePosix::ReleaseWriteFileDescriptor()
+{
+ const int fd = m_fds[WRITE];
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ return fd;
+}
+
+void
+PipePosix::Close()
+{
+ CloseReadFileDescriptor();
+ CloseWriteFileDescriptor();
+}
+
+Error
+PipePosix::Delete(llvm::StringRef name)
+{
+ return FileSystem::Unlink(name.data());
+}
+
+bool
+PipePosix::CanRead() const
+{
+ return m_fds[READ] != PipePosix::kInvalidDescriptor;
+}
+
+bool
+PipePosix::CanWrite() const
+{
+ return m_fds[WRITE] != PipePosix::kInvalidDescriptor;
+}
+
+void
+PipePosix::CloseReadFileDescriptor()
+{
+ if (CanRead())
+ {
+ close(m_fds[READ]);
+ m_fds[READ] = PipePosix::kInvalidDescriptor;
+ }
+}
+
+void
+PipePosix::CloseWriteFileDescriptor()
+{
+ if (CanWrite())
+ {
+ close(m_fds[WRITE]);
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ }
+}
+
+Error
+PipePosix::ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_read)
+{
+ bytes_read = 0;
+ if (!CanRead())
+ return Error(EINVAL, eErrorTypePOSIX);
+
+ auto handle = GetReadFileDescriptor();
+ return SelectIO(handle,
+ true,
+ [=, &bytes_read](bool &done)
+ {
+ Error error;
+ auto result = ::read(handle,
+ reinterpret_cast<char*>(buf) + bytes_read,
+ size - bytes_read);
+ if (result != -1)
+ {
+ bytes_read += result;
+ if (bytes_read == size || result == 0)
+ done = true;
+ }
+ else
+ error.SetErrorToErrno();
+
+ return error;
+ },
+ timeout);
+}
+
+Error
+PipePosix::Write(const void *buf, size_t size, size_t &bytes_written)
+{
+ bytes_written = 0;
+ if (!CanWrite())
+ return Error(EINVAL, eErrorTypePOSIX);
+
+ auto handle = GetWriteFileDescriptor();
+ return SelectIO(handle,
+ false,
+ [=, &bytes_written](bool &done)
+ {
+ Error error;
+ auto result = ::write(handle,
+ reinterpret_cast<const char*>(buf) + bytes_written,
+ size - bytes_written);
+ if (result != -1)
+ {
+ bytes_written += result;
+ if (bytes_written == size)
+ done = true;
+ }
+ else
+ error.SetErrorToErrno();
+
+ return error;
+ },
+ std::chrono::microseconds::zero());
+}
diff --git a/source/Host/posix/ProcessLauncherPosix.cpp b/source/Host/posix/ProcessLauncherPosix.cpp
new file mode 100644
index 000000000000..dd5c5121a97b
--- /dev/null
+++ b/source/Host/posix/ProcessLauncherPosix.cpp
@@ -0,0 +1,33 @@
+//===-- ProcessLauncherPosix.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/Host.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/posix/ProcessLauncherPosix.h"
+
+#include "lldb/Target/ProcessLaunchInfo.h"
+
+#include <limits.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostProcess
+ProcessLauncherPosix::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error)
+{
+ lldb::pid_t pid;
+ char exe_path[PATH_MAX];
+
+ launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
+
+ // TODO(zturner): Move the code from LaunchProcessPosixSpawn to here, and make MacOSX re-use this
+ // ProcessLauncher when it wants a posix_spawn launch.
+ error = Host::LaunchProcessPosixSpawn(exe_path, launch_info, pid);
+ return HostProcess(pid);
+}
diff --git a/source/Interpreter/Args.cpp b/source/Interpreter/Args.cpp
index 4831eaaac348..93933802f57c 100644
--- a/source/Interpreter/Args.cpp
+++ b/source/Interpreter/Args.cpp
@@ -685,7 +685,7 @@ Args::ParseOptions (Options &options)
}
}
// Call the callback with the option
- if (long_options_index >= 0)
+ if (long_options_index >= 0 && long_options[long_options_index].definition)
{
const OptionDefinition *def = long_options[long_options_index].definition;
CommandInterpreter &interpreter = options.GetInterpreter();
@@ -829,15 +829,18 @@ Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::add
options.SetTryAllThreads(true);
ExpressionResults expr_result = target->EvaluateExpression(s,
- exe_ctx->GetFramePtr(),
- valobj_sp,
- options);
+ exe_ctx->GetFramePtr(),
+ valobj_sp,
+ options);
bool success = false;
if (expr_result == eExpressionCompleted)
{
+ if (valobj_sp)
+ valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable(valobj_sp->GetDynamicValueType(), true);
// Get the address to watch.
- addr = valobj_sp->GetValueAsUnsigned(fail_value, &success);
+ if (valobj_sp)
+ addr = valobj_sp->GetValueAsUnsigned(fail_value, &success);
if (success)
{
if (error_ptr)
@@ -966,6 +969,26 @@ Args::StringToBoolean (const char *s, bool fail_value, bool *success_ptr)
return fail_value;
}
+char
+Args::StringToChar(const char *s, char fail_value, bool *success_ptr)
+{
+ bool success = false;
+ char result = fail_value;
+
+ if (s)
+ {
+ size_t length = strlen(s);
+ if (length == 1)
+ {
+ success = true;
+ result = s[0];
+ }
+ }
+ if (success_ptr)
+ *success_ptr = success;
+ return result;
+}
+
const char *
Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t &update)
{
diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp
index 56c8f8c0ad6a..176a1fc9a3b0 100644
--- a/source/Interpreter/CommandInterpreter.cpp
+++ b/source/Interpreter/CommandInterpreter.cpp
@@ -49,7 +49,9 @@
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/Timer.h"
+#ifndef LLDB_DISABLE_LIBEDIT
#include "lldb/Host/Editline.h"
+#endif
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
@@ -117,7 +119,11 @@ CommandInterpreter::CommandInterpreter
m_comment_char ('#'),
m_batch_command_mode (false),
m_truncation_warning(eNoTruncation),
- m_command_source_depth (0)
+ m_command_source_depth (0),
+ m_num_errors(0),
+ m_quit_requested(false),
+ m_stopped_for_crash(false)
+
{
debugger.SetScriptLanguage (script_language);
SetEventName (eBroadcastBitThreadShouldExit, "thread-should-exit");
@@ -333,7 +339,11 @@ CommandInterpreter::Initialize ()
#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
ProcessAliasOptionsArgs (cmd_obj_sp, "--", alias_arguments_vector_sp);
#else
- ProcessAliasOptionsArgs (cmd_obj_sp, "--shell=" LLDB_DEFAULT_SHELL " --", alias_arguments_vector_sp);
+ std::string shell_option;
+ shell_option.append("--shell=");
+ shell_option.append(HostInfo::GetDefaultShell().GetPath());
+ shell_option.append(" --");
+ ProcessAliasOptionsArgs (cmd_obj_sp, shell_option.c_str(), alias_arguments_vector_sp);
#endif
AddAlias ("r", cmd_obj_sp);
AddAlias ("run", cmd_obj_sp);
@@ -414,6 +424,7 @@ CommandInterpreter::LoadCommandDictionary ()
m_command_dict["watchpoint"]= CommandObjectSP (new CommandObjectMultiwordWatchpoint (*this));
const char *break_regexes[][2] = {{"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "breakpoint set --file '%1' --line %2"},
+ {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
{"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
{"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
{"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$", "breakpoint set --name '%1'"},
@@ -431,7 +442,8 @@ CommandInterpreter::LoadCommandDictionary ()
"_regexp-break [<filename>:<linenum>]\n_regexp-break [<linenum>]\n_regexp-break [<address>]\n_regexp-break <...>",
2,
CommandCompletions::eSymbolCompletion |
- CommandCompletions::eSourceFileCompletion));
+ CommandCompletions::eSourceFileCompletion,
+ false));
if (break_regex_cmd_ap.get())
{
@@ -458,7 +470,8 @@ CommandInterpreter::LoadCommandDictionary ()
"_regexp-tbreak [<filename>:<linenum>]\n_regexp-break [<linenum>]\n_regexp-break [<address>]\n_regexp-break <...>",
2,
CommandCompletions::eSymbolCompletion |
- CommandCompletions::eSourceFileCompletion));
+ CommandCompletions::eSourceFileCompletion,
+ false));
if (tbreak_regex_cmd_ap.get())
{
@@ -469,6 +482,8 @@ CommandInterpreter::LoadCommandDictionary ()
char buffer[1024];
int num_printed = snprintf(buffer, 1024, "%s %s", break_regexes[i][1], "-o");
assert (num_printed < 1024);
+ // Quiet unused variable warning for release builds.
+ (void) num_printed;
success = tbreak_regex_cmd_ap->AddRegexCommand (break_regexes[i][0], buffer);
if (!success)
break;
@@ -487,7 +502,9 @@ CommandInterpreter::LoadCommandDictionary ()
"_regexp-attach",
"Attach to a process id if in decimal, otherwise treat the argument as a process name to attach to.",
"_regexp-attach [<pid>]\n_regexp-attach [<process-name>]",
- 2));
+ 2,
+ 0,
+ false));
if (attach_regex_cmd_ap.get())
{
if (attach_regex_cmd_ap->AddRegexCommand("^([0-9]+)[[:space:]]*$", "process attach --pid %1") &&
@@ -504,7 +521,10 @@ CommandInterpreter::LoadCommandDictionary ()
down_regex_cmd_ap(new CommandObjectRegexCommand (*this,
"_regexp-down",
"Go down \"n\" frames in the stack (1 frame by default).",
- "_regexp-down [n]", 2));
+ "_regexp-down [n]",
+ 2,
+ 0,
+ false));
if (down_regex_cmd_ap.get())
{
if (down_regex_cmd_ap->AddRegexCommand("^$", "frame select -r -1") &&
@@ -519,7 +539,10 @@ CommandInterpreter::LoadCommandDictionary ()
up_regex_cmd_ap(new CommandObjectRegexCommand (*this,
"_regexp-up",
"Go up \"n\" frames in the stack (1 frame by default).",
- "_regexp-up [n]", 2));
+ "_regexp-up [n]",
+ 2,
+ 0,
+ false));
if (up_regex_cmd_ap.get())
{
if (up_regex_cmd_ap->AddRegexCommand("^$", "frame select -r 1") &&
@@ -534,7 +557,10 @@ CommandInterpreter::LoadCommandDictionary ()
display_regex_cmd_ap(new CommandObjectRegexCommand (*this,
"_regexp-display",
"Add an expression evaluation stop-hook.",
- "_regexp-display expression", 2));
+ "_regexp-display expression",
+ 2,
+ 0,
+ false));
if (display_regex_cmd_ap.get())
{
if (display_regex_cmd_ap->AddRegexCommand("^(.+)$", "target stop-hook add -o \"expr -- %1\""))
@@ -548,7 +574,10 @@ CommandInterpreter::LoadCommandDictionary ()
undisplay_regex_cmd_ap(new CommandObjectRegexCommand (*this,
"_regexp-undisplay",
"Remove an expression evaluation stop-hook.",
- "_regexp-undisplay stop-hook-number", 2));
+ "_regexp-undisplay stop-hook-number",
+ 2,
+ 0,
+ false));
if (undisplay_regex_cmd_ap.get())
{
if (undisplay_regex_cmd_ap->AddRegexCommand("^([0-9]+)$", "target stop-hook delete %1"))
@@ -562,7 +591,10 @@ CommandInterpreter::LoadCommandDictionary ()
connect_gdb_remote_cmd_ap(new CommandObjectRegexCommand (*this,
"gdb-remote",
"Connect to a remote GDB server. If no hostname is provided, localhost is assumed.",
- "gdb-remote [<hostname>:]<portnum>", 2));
+ "gdb-remote [<hostname>:]<portnum>",
+ 2,
+ 0,
+ false));
if (connect_gdb_remote_cmd_ap.get())
{
if (connect_gdb_remote_cmd_ap->AddRegexCommand("^([^:]+:[[:digit:]]+)$", "process connect --plugin gdb-remote connect://%1") &&
@@ -577,7 +609,10 @@ CommandInterpreter::LoadCommandDictionary ()
connect_kdp_remote_cmd_ap(new CommandObjectRegexCommand (*this,
"kdp-remote",
"Connect to a remote KDP server. udp port 41139 is the default port number.",
- "kdp-remote <hostname>[:<portnum>]", 2));
+ "kdp-remote <hostname>[:<portnum>]",
+ 2,
+ 0,
+ false));
if (connect_kdp_remote_cmd_ap.get())
{
if (connect_kdp_remote_cmd_ap->AddRegexCommand("^([^:]+:[[:digit:]]+)$", "process connect --plugin kdp-remote udp://%1") &&
@@ -590,9 +625,12 @@ CommandInterpreter::LoadCommandDictionary ()
std::unique_ptr<CommandObjectRegexCommand>
bt_regex_cmd_ap(new CommandObjectRegexCommand (*this,
- "_regexp-bt",
- "Show a backtrace. An optional argument is accepted; if that argument is a number, it specifies the number of frames to display. If that argument is 'all', full backtraces of all threads are displayed.",
- "bt [<digit>|all]", 2));
+ "_regexp-bt",
+ "Show a backtrace. An optional argument is accepted; if that argument is a number, it specifies the number of frames to display. If that argument is 'all', full backtraces of all threads are displayed.",
+ "bt [<digit>|all]",
+ 2,
+ 0,
+ false));
if (bt_regex_cmd_ap.get())
{
// accept but don't document "bt -c <number>" -- before bt was a regex command if you wanted to backtrace
@@ -614,7 +652,8 @@ CommandInterpreter::LoadCommandDictionary ()
"Implements the GDB 'list' command in all of its forms except FILE:FUNCTION and maps them to the appropriate 'source list' commands.",
"_regexp-list [<line>]\n_regexp-list [<file>:<line>]\n_regexp-list [<file>:<line>]",
2,
- CommandCompletions::eSourceFileCompletion));
+ CommandCompletions::eSourceFileCompletion,
+ false));
if (list_regex_cmd_ap.get())
{
if (list_regex_cmd_ap->AddRegexCommand("^([0-9]+)[[:space:]]*$", "source list --line %1") &&
@@ -634,7 +673,10 @@ CommandInterpreter::LoadCommandDictionary ()
env_regex_cmd_ap(new CommandObjectRegexCommand (*this,
"_regexp-env",
"Implements a shortcut to viewing and setting environment variables.",
- "_regexp-env\n_regexp-env FOO=BAR", 2));
+ "_regexp-env\n_regexp-env FOO=BAR",
+ 2,
+ 0,
+ false));
if (env_regex_cmd_ap.get())
{
if (env_regex_cmd_ap->AddRegexCommand("^$", "settings show target.env-vars") &&
@@ -652,7 +694,10 @@ CommandInterpreter::LoadCommandDictionary ()
"_regexp-jump [<line>]\n"
"_regexp-jump [<+-lineoffset>]\n"
"_regexp-jump [<file>:<line>]\n"
- "_regexp-jump [*<addr>]\n", 2));
+ "_regexp-jump [*<addr>]\n",
+ 2,
+ 0,
+ false));
if (jump_regex_cmd_ap.get())
{
if (jump_regex_cmd_ap->AddRegexCommand("^\\*(.*)$", "thread jump --addr %1") &&
@@ -1043,6 +1088,22 @@ CommandInterpreter::RemoveAlias (const char *alias_name)
}
return false;
}
+
+bool
+CommandInterpreter::RemoveCommand (const char *cmd)
+{
+ auto pos = m_command_dict.find(cmd);
+ if (pos != m_command_dict.end())
+ {
+ if (pos->second->IsRemovable())
+ {
+ // Only regular expression objects or python commands are removable
+ m_command_dict.erase(pos);
+ return true;
+ }
+ }
+ return false;
+}
bool
CommandInterpreter::RemoveUser (const char *alias_name)
{
@@ -1448,7 +1509,7 @@ CommandInterpreter::PreprocessCommand (std::string &command)
// Get a dummy target to allow for calculator mode while processing backticks.
// This also helps break the infinite loop caused when target is null.
if (!target)
- target = Host::GetDummyTarget(GetDebugger()).get();
+ target = m_debugger.GetDummyTarget();
if (target)
{
ValueObjectSP expr_result_valobj_sp;
@@ -1462,13 +1523,15 @@ CommandInterpreter::PreprocessCommand (std::string &command)
options.SetTimeoutUsec(0);
ExpressionResults expr_result = target->EvaluateExpression (expr_str.c_str(),
- exe_ctx.GetFramePtr(),
- expr_result_valobj_sp,
- options);
+ exe_ctx.GetFramePtr(),
+ expr_result_valobj_sp,
+ options);
if (expr_result == eExpressionCompleted)
{
Scalar scalar;
+ if (expr_result_valobj_sp)
+ expr_result_valobj_sp = expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(expr_result_valobj_sp->GetDynamicValueType(), true);
if (expr_result_valobj_sp->ResolveValue (scalar))
{
command.erase (start_backtick, end_backtick - start_backtick + 1);
@@ -2415,13 +2478,14 @@ CommandInterpreter::SourceInitFile (bool in_cwd, CommandReturnObject &result)
if (init_file.Exists())
{
const bool saved_batch = SetBatchCommandMode (true);
+ CommandInterpreterRunOptions options;
+ options.SetSilent (true);
+ options.SetStopOnError (false);
+ options.SetStopOnContinue (true);
+
HandleCommandsFromFile (init_file,
nullptr, // Execution context
- eLazyBoolYes, // Stop on continue
- eLazyBoolNo, // Stop on error
- eLazyBoolNo, // Don't echo commands
- eLazyBoolNo, // Don't print command output
- eLazyBoolNo, // Don't add the commands that are sourced into the history buffer
+ options,
result);
SetBatchCommandMode (saved_batch);
}
@@ -2451,12 +2515,8 @@ CommandInterpreter::GetPlatform (bool prefer_target_platform)
void
CommandInterpreter::HandleCommands (const StringList &commands,
- ExecutionContext *override_context,
- bool stop_on_continue,
- bool stop_on_error,
- bool echo_commands,
- bool print_results,
- LazyBool add_to_history,
+ ExecutionContext *override_context,
+ CommandInterpreterRunOptions &options,
CommandReturnObject &result)
{
size_t num_lines = commands.GetSize();
@@ -2472,7 +2532,7 @@ CommandInterpreter::HandleCommands (const StringList &commands,
if (override_context != nullptr)
UpdateExecutionContext (override_context);
- if (!stop_on_continue)
+ if (!options.GetStopOnContinue())
{
m_debugger.SetAsyncExecution (false);
}
@@ -2483,7 +2543,7 @@ CommandInterpreter::HandleCommands (const StringList &commands,
if (cmd[0] == '\0')
continue;
- if (echo_commands)
+ if (options.GetEchoCommands())
{
result.AppendMessageWithFormat ("%s %s\n",
m_debugger.GetPrompt(),
@@ -2496,16 +2556,16 @@ CommandInterpreter::HandleCommands (const StringList &commands,
// We might call into a regex or alias command, in which case the add_to_history will get lost. This
// m_command_source_depth dingus is the way we turn off adding to the history in that case, so set it up here.
- if (!add_to_history)
+ if (!options.GetAddToHistory())
m_command_source_depth++;
- bool success = HandleCommand(cmd, add_to_history, tmp_result,
+ bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result,
nullptr, /* override_context */
true, /* repeat_on_empty_command */
override_context != nullptr /* no_context_switching */);
- if (!add_to_history)
+ if (!options.GetAddToHistory())
m_command_source_depth--;
- if (print_results)
+ if (options.GetPrintResults())
{
if (tmp_result.Succeeded())
result.AppendMessageWithFormat("%s", tmp_result.GetOutputData());
@@ -2516,7 +2576,7 @@ CommandInterpreter::HandleCommands (const StringList &commands,
const char *error_msg = tmp_result.GetErrorData();
if (error_msg == nullptr || error_msg[0] == '\0')
error_msg = "<unknown error>.\n";
- if (stop_on_error)
+ if (options.GetStopOnError())
{
result.AppendErrorWithFormat("Aborting reading of commands after command #%" PRIu64 ": '%s' failed with %s",
(uint64_t)idx, cmd, error_msg);
@@ -2524,7 +2584,7 @@ CommandInterpreter::HandleCommands (const StringList &commands,
m_debugger.SetAsyncExecution (old_async_execution);
return;
}
- else if (print_results)
+ else if (options.GetPrintResults())
{
result.AppendMessageWithFormat ("Command #%" PRIu64 " '%s' failed with %s",
(uint64_t)idx + 1,
@@ -2545,7 +2605,7 @@ CommandInterpreter::HandleCommands (const StringList &commands,
if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult)
|| (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult))
{
- if (stop_on_continue)
+ if (options.GetStopOnContinue())
{
// If we caused the target to proceed, and we're going to stop in that case, set the
// status in our real result before returning. This is an error if the continue was not the
@@ -2562,6 +2622,42 @@ CommandInterpreter::HandleCommands (const StringList &commands,
return;
}
}
+
+ // Also check for "stop on crash here:
+ bool should_stop = false;
+ if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash())
+ {
+ TargetSP target_sp (m_debugger.GetTargetList().GetSelectedTarget());
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ {
+ for (ThreadSP thread_sp : process_sp->GetThreadList().Threads())
+ {
+ StopReason reason = thread_sp->GetStopReason();
+ if (reason == eStopReasonSignal || reason == eStopReasonException || reason == eStopReasonInstrumentation)
+ {
+ should_stop = true;
+ break;
+ }
+ }
+ }
+ }
+ if (should_stop)
+ {
+ if (idx != num_lines - 1)
+ result.AppendErrorWithFormat("Aborting reading of commands after command #%" PRIu64 ": '%s' stopped with a signal or exception.\n",
+ (uint64_t)idx + 1, cmd);
+ else
+ result.AppendMessageWithFormat("Command #%" PRIu64 " '%s' stopped with a signal or exception.\n", (uint64_t)idx + 1, cmd);
+
+ result.SetStatus(tmp_result.GetStatus());
+ m_debugger.SetAsyncExecution (old_async_execution);
+
+ return;
+ }
+ }
}
@@ -2576,17 +2672,14 @@ enum {
eHandleCommandFlagStopOnContinue = (1u << 0),
eHandleCommandFlagStopOnError = (1u << 1),
eHandleCommandFlagEchoCommand = (1u << 2),
- eHandleCommandFlagPrintResult = (1u << 3)
+ eHandleCommandFlagPrintResult = (1u << 3),
+ eHandleCommandFlagStopOnCrash = (1u << 4)
};
void
CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
ExecutionContext *context,
- LazyBool stop_on_continue,
- LazyBool stop_on_error,
- LazyBool echo_command,
- LazyBool print_result,
- LazyBool add_to_history,
+ CommandInterpreterRunOptions &options,
CommandReturnObject &result)
{
if (cmd_file.Exists())
@@ -2602,7 +2695,7 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
uint32_t flags = 0;
- if (stop_on_continue == eLazyBoolCalculate)
+ if (options.m_stop_on_continue == eLazyBoolCalculate)
{
if (m_command_source_flags.empty())
{
@@ -2614,12 +2707,12 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
flags |= eHandleCommandFlagStopOnContinue;
}
}
- else if (stop_on_continue == eLazyBoolYes)
+ else if (options.m_stop_on_continue == eLazyBoolYes)
{
flags |= eHandleCommandFlagStopOnContinue;
}
- if (stop_on_error == eLazyBoolCalculate)
+ if (options.m_stop_on_error == eLazyBoolCalculate)
{
if (m_command_source_flags.empty())
{
@@ -2631,12 +2724,25 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
flags |= eHandleCommandFlagStopOnError;
}
}
- else if (stop_on_error == eLazyBoolYes)
+ else if (options.m_stop_on_error == eLazyBoolYes)
{
flags |= eHandleCommandFlagStopOnError;
}
- if (echo_command == eLazyBoolCalculate)
+ if (options.GetStopOnCrash())
+ {
+ if (m_command_source_flags.empty())
+ {
+ // Echo command by default
+ flags |= eHandleCommandFlagStopOnCrash;
+ }
+ else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash)
+ {
+ flags |= eHandleCommandFlagStopOnCrash;
+ }
+ }
+
+ if (options.m_echo_commands == eLazyBoolCalculate)
{
if (m_command_source_flags.empty())
{
@@ -2648,12 +2754,12 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
flags |= eHandleCommandFlagEchoCommand;
}
}
- else if (echo_command == eLazyBoolYes)
+ else if (options.m_echo_commands == eLazyBoolYes)
{
flags |= eHandleCommandFlagEchoCommand;
}
- if (print_result == eLazyBoolCalculate)
+ if (options.m_print_results == eLazyBoolCalculate)
{
if (m_command_source_flags.empty())
{
@@ -2665,7 +2771,7 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
flags |= eHandleCommandFlagPrintResult;
}
}
- else if (print_result == eLazyBoolYes)
+ else if (options.m_print_results == eLazyBoolYes)
{
flags |= eHandleCommandFlagPrintResult;
}
@@ -2680,18 +2786,21 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
lldb::StreamFileSP empty_stream_sp;
m_command_source_flags.push_back(flags);
IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
+ IOHandler::Type::CommandInterpreter,
input_file_sp,
empty_stream_sp, // Pass in an empty stream so we inherit the top input reader output stream
empty_stream_sp, // Pass in an empty stream so we inherit the top input reader error stream
flags,
nullptr, // Pass in NULL for "editline_name" so no history is saved, or written
debugger.GetPrompt(),
+ NULL,
false, // Not multi-line
+ debugger.GetUseColor(),
0,
*this));
const bool old_async_execution = debugger.GetAsyncExecution();
- // Set synchronous execution if we not stopping when we continue
+ // Set synchronous execution if we are not stopping on continue
if ((flags & eHandleCommandFlagStopOnContinue) == 0)
debugger.SetAsyncExecution (false);
@@ -2715,7 +2824,7 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
else
{
result.AppendErrorWithFormat ("Error reading commands from file %s - file not found.\n",
- cmd_file.GetFilename().AsCString());
+ cmd_file.GetFilename().AsCString("<Unknown>"));
result.SetStatus (eReturnStatusFailed);
return;
}
@@ -3056,14 +3165,46 @@ CommandInterpreter::IOHandlerInputComplete (IOHandler &io_handler, std::string &
break;
case eReturnStatusFailed:
+ m_num_errors++;
if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError))
io_handler.SetIsDone(true);
break;
case eReturnStatusQuit:
+ m_quit_requested = true;
io_handler.SetIsDone(true);
break;
}
+
+ // Finally, if we're going to stop on crash, check that here:
+ if (!m_quit_requested
+ && result.GetDidChangeProcessState()
+ && io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash))
+ {
+ bool should_stop = false;
+ TargetSP target_sp (m_debugger.GetTargetList().GetSelectedTarget());
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ {
+ for (ThreadSP thread_sp : process_sp->GetThreadList().Threads())
+ {
+ StopReason reason = thread_sp->GetStopReason();
+ if (reason == eStopReasonSignal || reason == eStopReasonException || reason == eStopReasonInstrumentation)
+ {
+ should_stop = true;
+ break;
+ }
+ }
+ }
+ }
+ if (should_stop)
+ {
+ io_handler.SetIsDone(true);
+ m_stopped_for_crash = true;
+ }
+ }
}
bool
@@ -3092,9 +3233,12 @@ CommandInterpreter::GetLLDBCommandsFromIOHandler (const char *prompt,
{
Debugger &debugger = GetDebugger();
IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
+ IOHandler::Type::CommandList,
"lldb", // Name of input reader for history
prompt, // Prompt
+ NULL, // Continuation prompt
true, // Get multiple lines
+ debugger.GetUseColor(),
0, // Don't show line numbers
delegate)); // IOHandlerDelegate
@@ -3118,9 +3262,12 @@ CommandInterpreter::GetPythonCommandsFromIOHandler (const char *prompt,
{
Debugger &debugger = GetDebugger();
IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
+ IOHandler::Type::PythonCode,
"lldb-python", // Name of input reader for history
prompt, // Prompt
+ NULL, // Continuation prompt
true, // Get multiple lines
+ debugger.GetUseColor(),
0, // Don't show line numbers
delegate)); // IOHandlerDelegate
@@ -3141,28 +3288,64 @@ CommandInterpreter::IsActive ()
return m_debugger.IsTopIOHandler (m_command_io_handler_sp);
}
-void
-CommandInterpreter::RunCommandInterpreter(bool auto_handle_events,
- bool spawn_thread)
+lldb::IOHandlerSP
+CommandInterpreter::GetIOHandler(bool force_create, CommandInterpreterRunOptions *options)
{
- // Only get one line at a time
- const bool multiple_lines = false;
-
// Always re-create the IOHandlerEditline in case the input
// changed. The old instance might have had a non-interactive
// input and now it does or vice versa.
- m_command_io_handler_sp.reset(new IOHandlerEditline (m_debugger,
- m_debugger.GetInputFile(),
- m_debugger.GetOutputFile(),
- m_debugger.GetErrorFile(),
- eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult,
- "lldb",
- m_debugger.GetPrompt(),
- multiple_lines,
- 0, // Don't show line numbers
- *this));
-
- m_debugger.PushIOHandler(m_command_io_handler_sp);
+ if (force_create || !m_command_io_handler_sp)
+ {
+ // Always re-create the IOHandlerEditline in case the input
+ // changed. The old instance might have had a non-interactive
+ // input and now it does or vice versa.
+ uint32_t flags = 0;
+
+ if (options)
+ {
+ if (options->m_stop_on_continue == eLazyBoolYes)
+ flags |= eHandleCommandFlagStopOnContinue;
+ if (options->m_stop_on_error == eLazyBoolYes)
+ flags |= eHandleCommandFlagStopOnError;
+ if (options->m_stop_on_crash == eLazyBoolYes)
+ flags |= eHandleCommandFlagStopOnCrash;
+ if (options->m_echo_commands != eLazyBoolNo)
+ flags |= eHandleCommandFlagEchoCommand;
+ if (options->m_print_results != eLazyBoolNo)
+ flags |= eHandleCommandFlagPrintResult;
+ }
+ else
+ {
+ flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult;
+ }
+
+ m_command_io_handler_sp.reset(new IOHandlerEditline (m_debugger,
+ IOHandler::Type::CommandInterpreter,
+ m_debugger.GetInputFile(),
+ m_debugger.GetOutputFile(),
+ m_debugger.GetErrorFile(),
+ flags,
+ "lldb",
+ m_debugger.GetPrompt(),
+ NULL, // Continuation prompt
+ false, // Don't enable multiple line input, just single line commands
+ m_debugger.GetUseColor(),
+ 0, // Don't show line numbers
+ *this));
+ }
+ return m_command_io_handler_sp;
+}
+
+void
+CommandInterpreter::RunCommandInterpreter(bool auto_handle_events,
+ bool spawn_thread,
+ CommandInterpreterRunOptions &options)
+{
+ // Always re-create the command intepreter when we run it in case
+ // any file handles have changed.
+ bool force_create = true;
+ m_debugger.PushIOHandler(GetIOHandler(force_create, &options));
+ m_stopped_for_crash = false;
if (auto_handle_events)
m_debugger.StartEventHandlerThread();
@@ -3174,10 +3357,10 @@ CommandInterpreter::RunCommandInterpreter(bool auto_handle_events,
else
{
m_debugger.ExecuteIOHanders();
-
+
if (auto_handle_events)
m_debugger.StopEventHandlerThread();
}
-
+
}
diff --git a/source/Interpreter/CommandObject.cpp b/source/Interpreter/CommandObject.cpp
index 3fdbf994fe7a..753e720b0f6e 100644
--- a/source/Interpreter/CommandObject.cpp
+++ b/source/Interpreter/CommandObject.cpp
@@ -49,7 +49,7 @@ CommandObject::CommandObject
uint32_t flags
) :
m_interpreter (interpreter),
- m_cmd_name (name),
+ m_cmd_name (name ? name : ""),
m_cmd_help_short (),
m_cmd_help_long (),
m_cmd_syntax (),
@@ -236,19 +236,34 @@ CommandObject::CheckRequirements (CommandReturnObject &result)
if ((flags & eFlagRequiresProcess) && !m_exe_ctx.HasProcessScope())
{
- result.AppendError (GetInvalidProcessDescription());
+ if (!m_exe_ctx.HasTargetScope())
+ result.AppendError (GetInvalidTargetDescription());
+ else
+ result.AppendError (GetInvalidProcessDescription());
return false;
}
if ((flags & eFlagRequiresThread) && !m_exe_ctx.HasThreadScope())
{
- result.AppendError (GetInvalidThreadDescription());
+ if (!m_exe_ctx.HasTargetScope())
+ result.AppendError (GetInvalidTargetDescription());
+ else if (!m_exe_ctx.HasProcessScope())
+ result.AppendError (GetInvalidProcessDescription());
+ else
+ result.AppendError (GetInvalidThreadDescription());
return false;
}
if ((flags & eFlagRequiresFrame) && !m_exe_ctx.HasFrameScope())
{
- result.AppendError (GetInvalidFrameDescription());
+ if (!m_exe_ctx.HasTargetScope())
+ result.AppendError (GetInvalidTargetDescription());
+ else if (!m_exe_ctx.HasProcessScope())
+ result.AppendError (GetInvalidProcessDescription());
+ else if (!m_exe_ctx.HasThreadScope())
+ result.AppendError (GetInvalidThreadDescription());
+ else
+ result.AppendError (GetInvalidFrameDescription());
return false;
}
@@ -733,6 +748,22 @@ BreakpointIDRangeHelpTextCallback ()
}
static const char *
+BreakpointNameHelpTextCallback ()
+{
+ return "A name that can be added to a breakpoint when it is created, or later "
+ "on with the \"breakpoint name add\" command. "
+ "Breakpoint names can be used to specify breakpoints in all the places breakpoint ID's "
+ "and breakpoint ID ranges can be used. As such they provide a convenient way to group breakpoints, "
+ "and to operate on breakpoints you create without having to track the breakpoint number. "
+ "Note, the attributes you set when using a breakpoint name in a breakpoint command don't "
+ "adhere to the name, but instead are set individually on all the breakpoints currently tagged with that name. Future breakpoints "
+ "tagged with that name will not pick up the attributes previously given using that name. "
+ "In order to distinguish breakpoint names from breakpoint ID's and ranges, "
+ "names must start with a letter from a-z or A-Z and cannot contain spaces, \".\" or \"-\". "
+ "Also, breakpoint names can only be applied to breakpoints, not to breakpoint locations.";
+}
+
+static const char *
GDBFormatHelpTextCallback ()
{
return "A GDB format consists of a repeat count, a format letter and a size letter. "
@@ -1003,6 +1034,18 @@ CommandObject::GetArgumentDescriptionAsCString (const lldb::CommandArgumentType
return nullptr;
}
+Target *
+CommandObject::GetDummyTarget()
+{
+ return m_interpreter.GetDebugger().GetDummyTarget();
+}
+
+Target *
+CommandObject::GetSelectedOrDummyTarget(bool prefer_dummy)
+{
+ return m_interpreter.GetDebugger().GetSelectedOrDummyTarget(prefer_dummy);
+}
+
bool
CommandObjectParsed::Execute (const char *args_string, CommandReturnObject &result)
{
@@ -1085,6 +1128,7 @@ CommandObject::g_arguments_data[] =
{ eArgTypeBoolean, "boolean", CommandCompletions::eNoCompletion, { nullptr, false }, "A Boolean value: 'true' or 'false'" },
{ eArgTypeBreakpointID, "breakpt-id", CommandCompletions::eNoCompletion, { BreakpointIDHelpTextCallback, false }, nullptr },
{ eArgTypeBreakpointIDRange, "breakpt-id-list", CommandCompletions::eNoCompletion, { BreakpointIDRangeHelpTextCallback, false }, nullptr },
+ { eArgTypeBreakpointName, "breakpoint-name", CommandCompletions::eNoCompletion, { BreakpointNameHelpTextCallback, false }, nullptr },
{ eArgTypeByteSize, "byte-size", CommandCompletions::eNoCompletion, { nullptr, false }, "Number of bytes to use." },
{ eArgTypeClassName, "class-name", CommandCompletions::eNoCompletion, { nullptr, false }, "Then name of a class from the debug information in the program." },
{ eArgTypeCommandName, "cmd-name", CommandCompletions::eNoCompletion, { nullptr, false }, "A debugger command (may be multiple words), without any options or arguments." },
@@ -1103,6 +1147,7 @@ CommandObject::g_arguments_data[] =
{ eArgTypeFunctionName, "function-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a function." },
{ eArgTypeFunctionOrSymbol, "function-or-symbol", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a function or symbol." },
{ eArgTypeGDBFormat, "gdb-format", CommandCompletions::eNoCompletion, { GDBFormatHelpTextCallback, true }, nullptr },
+ { eArgTypeHelpText, "help-text", CommandCompletions::eNoCompletion, { nullptr, false }, "Text to be used as help for some other entity in LLDB" },
{ eArgTypeIndex, "index", CommandCompletions::eNoCompletion, { nullptr, false }, "An index into a list." },
{ eArgTypeLanguage, "language", CommandCompletions::eNoCompletion, { LanguageTypeHelpTextCallback, true }, nullptr },
{ eArgTypeLineNum, "linenum", CommandCompletions::eNoCompletion, { nullptr, false }, "Line number in a source file." },
diff --git a/source/Interpreter/CommandObjectRegexCommand.cpp b/source/Interpreter/CommandObjectRegexCommand.cpp
index d27320dd1f3d..efc7c33fa8f6 100644
--- a/source/Interpreter/CommandObjectRegexCommand.cpp
+++ b/source/Interpreter/CommandObjectRegexCommand.cpp
@@ -31,12 +31,14 @@ CommandObjectRegexCommand::CommandObjectRegexCommand
const char *help,
const char *syntax,
uint32_t max_matches,
- uint32_t completion_type_mask
+ uint32_t completion_type_mask,
+ bool is_removable
) :
CommandObjectRaw (interpreter, name, help, syntax),
m_max_matches (max_matches),
m_completion_type_mask (completion_type_mask),
- m_entries ()
+ m_entries (),
+ m_is_removable (is_removable)
{
}
diff --git a/source/Interpreter/OptionGroupPlatform.cpp b/source/Interpreter/OptionGroupPlatform.cpp
index 9ffd5f072d90..7e5e1245a79f 100644
--- a/source/Interpreter/OptionGroupPlatform.cpp
+++ b/source/Interpreter/OptionGroupPlatform.cpp
@@ -33,7 +33,7 @@ OptionGroupPlatform::CreatePlatformWithOptions (CommandInterpreter &interpreter,
if (!m_platform_name.empty())
{
- platform_sp = Platform::Create (m_platform_name.c_str(), error);
+ platform_sp = Platform::Create (ConstString(m_platform_name.c_str()), error);
if (platform_sp)
{
if (platform_arch.IsValid() && !platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
diff --git a/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/source/Interpreter/OptionGroupValueObjectDisplay.cpp
index 125e5fb0a5d6..b6c63fa44c40 100644
--- a/source/Interpreter/OptionGroupValueObjectDisplay.cpp
+++ b/source/Interpreter/OptionGroupValueObjectDisplay.cpp
@@ -45,6 +45,7 @@ g_option_table[] =
{ LLDB_OPT_SET_1, false, "no-summary-depth", 'Y', OptionParser::eOptionalArgument, nullptr, nullptr, 0, eArgTypeCount, "Set the depth at which omitting summary information stops (default is 1)."},
{ LLDB_OPT_SET_1, false, "raw-output", 'R', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use formatting options."},
{ LLDB_OPT_SET_1, false, "show-all-children", 'A', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Ignore the upper bound on the number of children to show."},
+ { LLDB_OPT_SET_1, false, "validate", 'V', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Show results of type validators."},
{ 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr }
};
@@ -115,6 +116,13 @@ OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter,
if (!success)
error.SetErrorStringWithFormat("invalid synthetic-type '%s'", option_arg);
break;
+
+ case 'V':
+ run_validator = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid validate '%s'", option_arg);
+ break;
+
default:
error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
break;
@@ -137,6 +145,7 @@ OptionGroupValueObjectDisplay::OptionParsingStarting (CommandInterpreter &interp
use_synth = true;
be_raw = false;
ignore_cap = false;
+ run_validator = false;
Target *target = interpreter.GetExecutionContext().GetTargetPtr();
if (target != nullptr)
@@ -176,7 +185,9 @@ OptionGroupValueObjectDisplay::GetAsDumpOptions (LanguageRuntimeDescriptionDispl
.SetHideValue(use_objc);
if (be_raw)
- options.SetRawDisplay(true);
+ options.SetRawDisplay();
+
+ options.SetRunValidator(run_validator);
return options;
}
diff --git a/source/Interpreter/OptionValue.cpp b/source/Interpreter/OptionValue.cpp
index bc1e1c4c4779..a08a6127db15 100644
--- a/source/Interpreter/OptionValue.cpp
+++ b/source/Interpreter/OptionValue.cpp
@@ -71,6 +71,21 @@ OptionValue::GetAsBoolean () const
return nullptr;
}
+const OptionValueChar *
+OptionValue::GetAsChar () const
+{
+ if (GetType () == OptionValue::eTypeChar)
+ return static_cast<const OptionValueChar *>(this);
+ return nullptr;
+}
+
+OptionValueChar *
+OptionValue::GetAsChar ()
+{
+ if (GetType () == OptionValue::eTypeChar)
+ return static_cast<OptionValueChar *>(this);
+ return nullptr;
+}
OptionValueFileSpec *
OptionValue::GetAsFileSpec ()
@@ -342,6 +357,27 @@ OptionValue::SetBooleanValue (bool new_value)
return false;
}
+char
+OptionValue::GetCharValue(char fail_value) const
+{
+ const OptionValueChar *option_value = GetAsChar();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return fail_value;
+}
+
+char
+OptionValue::SetCharValue(char new_value)
+{
+ OptionValueChar *option_value = GetAsChar();
+ if (option_value)
+ {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
int64_t
OptionValue::GetEnumerationValue (int64_t fail_value) const
{
@@ -520,6 +556,8 @@ OptionValue::GetBuiltinTypeAsCString (Type t)
case eTypeArgs: return "arguments";
case eTypeArray: return "array";
case eTypeBoolean: return "boolean";
+ case eTypeChar:
+ return "char";
case eTypeDictionary: return "dictionary";
case eTypeEnum: return "enum";
case eTypeFileSpec: return "file";
@@ -547,6 +585,7 @@ OptionValue::CreateValueFromCStringForTypeMask (const char *value_cstr, uint32_t
{
case 1u << eTypeArch: value_sp.reset(new OptionValueArch()); break;
case 1u << eTypeBoolean: value_sp.reset(new OptionValueBoolean(false)); break;
+ case 1u << eTypeChar: value_sp.reset(new OptionValueChar('\0')); break;
case 1u << eTypeFileSpec: value_sp.reset(new OptionValueFileSpec()); break;
case 1u << eTypeFormat: value_sp.reset(new OptionValueFormat(eFormatInvalid)); break;
case 1u << eTypeSInt64: value_sp.reset(new OptionValueSInt64()); break;
diff --git a/source/Interpreter/OptionValueArch.cpp b/source/Interpreter/OptionValueArch.cpp
index 6d283d6b9275..7df149234bda 100644
--- a/source/Interpreter/OptionValueArch.cpp
+++ b/source/Interpreter/OptionValueArch.cpp
@@ -50,6 +50,7 @@ OptionValueArch::SetValueFromCString (const char *value_cstr, VarSetOperationTyp
{
case eVarSetOperationClear:
Clear();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -57,7 +58,10 @@ OptionValueArch::SetValueFromCString (const char *value_cstr, VarSetOperationTyp
if (value_cstr && value_cstr[0])
{
if (m_current_value.SetTriple (value_cstr))
+ {
m_value_was_set = true;
+ NotifyValueChanged();
+ }
else
error.SetErrorStringWithFormat("unsupported architecture '%s'", value_cstr);
}
diff --git a/source/Interpreter/OptionValueArray.cpp b/source/Interpreter/OptionValueArray.cpp
index 769aadd7b308..c0d48c1e7bd2 100644
--- a/source/Interpreter/OptionValueArray.cpp
+++ b/source/Interpreter/OptionValueArray.cpp
@@ -53,6 +53,7 @@ OptionValueArray::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint
break;
case eTypeBoolean:
+ case eTypeChar:
case eTypeEnum:
case eTypeFileSpec:
case eTypeFormat:
@@ -75,6 +76,7 @@ Error
OptionValueArray::SetValueFromCString (const char *value, VarSetOperationType op)
{
Args args(value);
+ NotifyValueChanged();
return SetArgs (args, op);
}
diff --git a/source/Interpreter/OptionValueBoolean.cpp b/source/Interpreter/OptionValueBoolean.cpp
index bf153a1442c7..71cc2afb98e1 100644
--- a/source/Interpreter/OptionValueBoolean.cpp
+++ b/source/Interpreter/OptionValueBoolean.cpp
@@ -45,6 +45,7 @@ OptionValueBoolean::SetValueFromCString (const char *value_cstr,
{
case eVarSetOperationClear:
Clear();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -56,6 +57,7 @@ OptionValueBoolean::SetValueFromCString (const char *value_cstr,
{
m_value_was_set = true;
m_current_value = value;
+ NotifyValueChanged();
}
else
{
diff --git a/source/Interpreter/OptionValueChar.cpp b/source/Interpreter/OptionValueChar.cpp
new file mode 100644
index 000000000000..7a0135314c81
--- /dev/null
+++ b/source/Interpreter/OptionValueChar.cpp
@@ -0,0 +1,80 @@
+//===-- OptionValueChar.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/OptionValueChar.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Interpreter/Args.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueChar::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 (" = ");
+ if (m_current_value != '\0')
+ strm.PutChar(m_current_value);
+ else
+ strm.PutCString("(null)");
+ }
+}
+
+Error
+OptionValueChar::SetValueFromCString (const char *value_cstr,
+ VarSetOperationType op)
+{
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ {
+ bool success = false;
+ char char_value = Args::StringToChar(value_cstr, '\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);
+ }
+ break;
+
+ default:
+ error = OptionValue::SetValueFromCString (value_cstr, op);
+ break;
+ }
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueChar::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueChar(*this));
+}
+
+
diff --git a/source/Interpreter/OptionValueDictionary.cpp b/source/Interpreter/OptionValueDictionary.cpp
index b560937141b3..e5299f8cc390 100644
--- a/source/Interpreter/OptionValueDictionary.cpp
+++ b/source/Interpreter/OptionValueDictionary.cpp
@@ -64,6 +64,7 @@ OptionValueDictionary::DumpValue (const ExecutionContext *exe_ctx, Stream &strm,
break;
case eTypeBoolean:
+ case eTypeChar:
case eTypeEnum:
case eTypeFileSpec:
case eTypeFormat:
@@ -220,7 +221,10 @@ Error
OptionValueDictionary::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
{
Args args(value_cstr);
- return SetArgs (args, op);
+ Error error = SetArgs (args, op);
+ if (error.Success())
+ NotifyValueChanged();
+ return error;
}
lldb::OptionValueSP
diff --git a/source/Interpreter/OptionValueEnumeration.cpp b/source/Interpreter/OptionValueEnumeration.cpp
index 7aceac91b601..dbaeb185fa3a 100644
--- a/source/Interpreter/OptionValueEnumeration.cpp
+++ b/source/Interpreter/OptionValueEnumeration.cpp
@@ -62,6 +62,7 @@ OptionValueEnumeration::SetValueFromCString (const char *value, VarSetOperationT
{
case eVarSetOperationClear:
Clear ();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -73,6 +74,7 @@ OptionValueEnumeration::SetValueFromCString (const char *value, VarSetOperationT
if (enumerator_entry)
{
m_current_value = enumerator_entry->value.value;
+ NotifyValueChanged();
}
else
{
diff --git a/source/Interpreter/OptionValueFileSpec.cpp b/source/Interpreter/OptionValueFileSpec.cpp
index c8aaadef23bc..3f466985a83a 100644
--- a/source/Interpreter/OptionValueFileSpec.cpp
+++ b/source/Interpreter/OptionValueFileSpec.cpp
@@ -78,6 +78,7 @@ OptionValueFileSpec::SetValueFromCString (const char *value_cstr,
{
case eVarSetOperationClear:
Clear ();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -100,6 +101,7 @@ OptionValueFileSpec::SetValueFromCString (const char *value_cstr,
m_value_was_set = true;
m_current_value.SetFile(filepath.c_str(), true);
m_data_sp.reset();
+ NotifyValueChanged();
}
else
{
diff --git a/source/Interpreter/OptionValueFileSpecLIst.cpp b/source/Interpreter/OptionValueFileSpecLIst.cpp
index e493c70d5a55..7150ad474643 100644
--- a/source/Interpreter/OptionValueFileSpecLIst.cpp
+++ b/source/Interpreter/OptionValueFileSpecLIst.cpp
@@ -51,6 +51,7 @@ OptionValueFileSpecList::SetValueFromCString (const char *value, VarSetOperation
{
case eVarSetOperationClear:
Clear ();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -72,6 +73,7 @@ OptionValueFileSpecList::SetValueFromCString (const char *value, VarSetOperation
else
m_current_value.Append(file);
}
+ NotifyValueChanged();
}
}
else
@@ -94,6 +96,7 @@ OptionValueFileSpecList::SetValueFromCString (const char *value, VarSetOperation
FileSpec file (args.GetArgumentAtIndex(i), false);
m_current_value.Append(file);
}
+ NotifyValueChanged();
}
else
{
@@ -120,6 +123,7 @@ OptionValueFileSpecList::SetValueFromCString (const char *value, VarSetOperation
FileSpec file (args.GetArgumentAtIndex(i), false);
m_current_value.Insert (idx, file);
}
+ NotifyValueChanged();
}
}
else
@@ -155,6 +159,7 @@ OptionValueFileSpecList::SetValueFromCString (const char *value, VarSetOperation
m_current_value.Remove (j);
}
}
+ NotifyValueChanged();
}
else
{
@@ -172,9 +177,6 @@ OptionValueFileSpecList::SetValueFromCString (const char *value, VarSetOperation
break;
}
return error;
-
- m_value_was_set = true;
- return Error();
}
lldb::OptionValueSP
diff --git a/source/Interpreter/OptionValueFormat.cpp b/source/Interpreter/OptionValueFormat.cpp
index 296dd983208c..d91f10b0edeb 100644
--- a/source/Interpreter/OptionValueFormat.cpp
+++ b/source/Interpreter/OptionValueFormat.cpp
@@ -43,6 +43,7 @@ OptionValueFormat::SetValueFromCString (const char *value_cstr, VarSetOperationT
{
case eVarSetOperationClear:
Clear();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -54,6 +55,7 @@ OptionValueFormat::SetValueFromCString (const char *value_cstr, VarSetOperationT
{
m_value_was_set = true;
m_current_value = new_format;
+ NotifyValueChanged();
}
}
break;
diff --git a/source/Interpreter/OptionValuePathMappings.cpp b/source/Interpreter/OptionValuePathMappings.cpp
index 88a0eb7d6a3b..56f2ecf4f5fe 100644
--- a/source/Interpreter/OptionValuePathMappings.cpp
+++ b/source/Interpreter/OptionValuePathMappings.cpp
@@ -43,6 +43,7 @@ OptionValuePathMappings::SetValueFromCString (const char *value, VarSetOperation
{
case eVarSetOperationClear:
Clear ();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -64,6 +65,7 @@ OptionValuePathMappings::SetValueFromCString (const char *value, VarSetOperation
if (!m_path_mappings.Replace (a, b, idx, m_notify_changes))
m_path_mappings.Append(a, b, m_notify_changes);
}
+ NotifyValueChanged();
}
}
else
@@ -97,6 +99,7 @@ OptionValuePathMappings::SetValueFromCString (const char *value, VarSetOperation
m_path_mappings.Append(a, b, m_notify_changes);
m_value_was_set = true;
}
+ NotifyValueChanged();
}
break;
@@ -121,6 +124,7 @@ OptionValuePathMappings::SetValueFromCString (const char *value, VarSetOperation
ConstString b(args.GetArgumentAtIndex(i+1));
m_path_mappings.Insert (a, b, idx, m_notify_changes);
}
+ NotifyValueChanged();
}
}
else
@@ -156,6 +160,7 @@ OptionValuePathMappings::SetValueFromCString (const char *value, VarSetOperation
m_path_mappings.Remove (j, m_notify_changes);
}
}
+ NotifyValueChanged();
}
else
{
@@ -173,9 +178,6 @@ OptionValuePathMappings::SetValueFromCString (const char *value, VarSetOperation
break;
}
return error;
-
- m_value_was_set = true;
- return Error();
}
lldb::OptionValueSP
diff --git a/source/Interpreter/OptionValueProperties.cpp b/source/Interpreter/OptionValueProperties.cpp
index 0497ee1c15d7..6ec2aa569fa3 100644
--- a/source/Interpreter/OptionValueProperties.cpp
+++ b/source/Interpreter/OptionValueProperties.cpp
@@ -81,6 +81,16 @@ OptionValueProperties::Initialize (const PropertyDefinition *defs)
}
void
+OptionValueProperties::SetValueChangedCallback (uint32_t property_idx,
+ OptionValueChangedCallback callback,
+ void *baton)
+{
+ Property *property = ProtectedGetPropertyAtIndex (property_idx);
+ if (property)
+ property->SetValueChangedCallback (callback, baton);
+}
+
+void
OptionValueProperties::AppendProperty(const ConstString &name,
const ConstString &desc,
bool is_global,
diff --git a/source/Interpreter/OptionValueRegex.cpp b/source/Interpreter/OptionValueRegex.cpp
index f1ba0ed04d6c..f51cf02edf56 100644
--- a/source/Interpreter/OptionValueRegex.cpp
+++ b/source/Interpreter/OptionValueRegex.cpp
@@ -57,6 +57,7 @@ OptionValueRegex::SetValueFromCString (const char *value_cstr,
case eVarSetOperationClear:
Clear();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -64,6 +65,7 @@ OptionValueRegex::SetValueFromCString (const char *value_cstr,
if (m_regex.Compile (value_cstr, m_regex.GetCompileFlags()))
{
m_value_was_set = true;
+ NotifyValueChanged();
}
else
{
diff --git a/source/Interpreter/OptionValueSInt64.cpp b/source/Interpreter/OptionValueSInt64.cpp
index 04bf9306ade6..1827cc1d873f 100644
--- a/source/Interpreter/OptionValueSInt64.cpp
+++ b/source/Interpreter/OptionValueSInt64.cpp
@@ -44,6 +44,7 @@ OptionValueSInt64::SetValueFromCString (const char *value_cstr, VarSetOperationT
{
case eVarSetOperationClear:
Clear();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -57,6 +58,7 @@ OptionValueSInt64::SetValueFromCString (const char *value_cstr, VarSetOperationT
{
m_value_was_set = true;
m_current_value = value;
+ NotifyValueChanged();
}
else
error.SetErrorStringWithFormat ("%" PRIi64 " is out of range, valid values must be between %" PRIi64 " and %" PRIi64 ".",
diff --git a/source/Interpreter/OptionValueString.cpp b/source/Interpreter/OptionValueString.cpp
index df047bd98996..a1b80d8fc4f6 100644
--- a/source/Interpreter/OptionValueString.cpp
+++ b/source/Interpreter/OptionValueString.cpp
@@ -94,30 +94,32 @@ OptionValueString::SetValueFromCString (const char *value_cstr,
case eVarSetOperationAppend:
{
- std::string new_value(m_current_value);
- if (value_cstr && value_cstr[0])
- {
- if (m_options.Test (eOptionEncodeCharacterEscapeSequences))
+ std::string new_value(m_current_value);
+ if (value_cstr && value_cstr[0])
{
- std::string str;
- Args::EncodeEscapeSequences (value_cstr, str);
- new_value.append(str);
+ if (m_options.Test (eOptionEncodeCharacterEscapeSequences))
+ {
+ std::string str;
+ Args::EncodeEscapeSequences (value_cstr, str);
+ new_value.append(str);
+ }
+ else
+ new_value.append(value_cstr);
}
- else
- new_value.append(value_cstr);
- }
- if (m_validator)
- {
- error = m_validator(new_value.c_str(),m_validator_baton);
- if (error.Fail())
- return error;
- }
- m_current_value.assign(new_value);
+ if (m_validator)
+ {
+ error = m_validator(new_value.c_str(),m_validator_baton);
+ if (error.Fail())
+ return error;
+ }
+ m_current_value.assign(new_value);
+ NotifyValueChanged();
}
break;
case eVarSetOperationClear:
Clear ();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -137,6 +139,7 @@ OptionValueString::SetValueFromCString (const char *value_cstr,
{
SetCurrentValue (value_cstr);
}
+ NotifyValueChanged();
break;
}
return error;
diff --git a/source/Interpreter/OptionValueUInt64.cpp b/source/Interpreter/OptionValueUInt64.cpp
index 56b3a1c74702..3e12c030255c 100644
--- a/source/Interpreter/OptionValueUInt64.cpp
+++ b/source/Interpreter/OptionValueUInt64.cpp
@@ -51,6 +51,7 @@ OptionValueUInt64::SetValueFromCString (const char *value_cstr, VarSetOperationT
{
case eVarSetOperationClear:
Clear ();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -62,6 +63,7 @@ OptionValueUInt64::SetValueFromCString (const char *value_cstr, VarSetOperationT
{
m_value_was_set = true;
m_current_value = value;
+ NotifyValueChanged();
}
else
{
diff --git a/source/Interpreter/OptionValueUUID.cpp b/source/Interpreter/OptionValueUUID.cpp
index 0141911d97ad..c228cf6e415e 100644
--- a/source/Interpreter/OptionValueUUID.cpp
+++ b/source/Interpreter/OptionValueUUID.cpp
@@ -45,6 +45,7 @@ OptionValueUUID::SetValueFromCString (const char *value_cstr,
{
case eVarSetOperationClear:
Clear();
+ NotifyValueChanged();
break;
case eVarSetOperationReplace:
@@ -53,7 +54,10 @@ OptionValueUUID::SetValueFromCString (const char *value_cstr,
if (m_uuid.SetFromCString(value_cstr) == 0)
error.SetErrorStringWithFormat ("invalid uuid string value '%s'", value_cstr);
else
+ {
m_value_was_set = true;
+ NotifyValueChanged();
+ }
}
break;
diff --git a/source/Interpreter/Property.cpp b/source/Interpreter/Property.cpp
index 49376266b077..7f7219fc0d50 100644
--- a/source/Interpreter/Property.cpp
+++ b/source/Interpreter/Property.cpp
@@ -60,7 +60,11 @@ Property::Property (const PropertyDefinition &definition) :
else
m_value_sp.reset (new OptionValueBoolean(definition.default_uint_value != 0));
break;
-
+
+ case OptionValue::eTypeChar:
+ m_value_sp.reset(new OptionValueChar(Args::StringToChar(definition.default_cstr_value, '\0', nullptr)));
+ break;
+
case OptionValue::eTypeDictionary:
// "definition.default_uint_value" is always a OptionValue::Type
m_value_sp.reset (new OptionValueDictionary(OptionValue::ConvertTypeToMask((OptionValue::Type)definition.default_uint_value)));
@@ -273,3 +277,12 @@ Property::DumpDescription (CommandInterpreter &interpreter,
}
}
+
+void
+Property::SetValueChangedCallback (OptionValueChangedCallback callback, void *baton)
+{
+ if (m_value_sp)
+ m_value_sp->SetValueChangedCallback (callback, baton);
+}
+
+
diff --git a/source/Interpreter/ScriptInterpreter.cpp b/source/Interpreter/ScriptInterpreter.cpp
index b6c46f83bd92..45e3b44cc0ac 100644
--- a/source/Interpreter/ScriptInterpreter.cpp
+++ b/source/Interpreter/ScriptInterpreter.cpp
@@ -124,6 +124,7 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call
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,
@@ -131,7 +132,10 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call
SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame,
- SWIGPython_GetDynamicSetting swig_plugin_get)
+ 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,
@@ -146,6 +150,7 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call
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,
@@ -153,6 +158,9 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call
swig_run_script_keyword_thread,
swig_run_script_keyword_target,
swig_run_script_keyword_frame,
- swig_plugin_get);
+ 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/ScriptInterpreterPython.cpp b/source/Interpreter/ScriptInterpreterPython.cpp
index 1b24fea7c218..ab151073f9e9 100644
--- a/source/Interpreter/ScriptInterpreterPython.cpp
+++ b/source/Interpreter/ScriptInterpreterPython.cpp
@@ -28,15 +28,20 @@
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Breakpoint/WatchpointOptions.h"
#include "lldb/Core/Communication.h"
-#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Timer.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Pipe.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/PythonDataObjects.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+
+#if defined(_WIN32)
+#include "lldb/Host/windows/ConnectionGenericFileWindows.h"
+#endif
using namespace lldb;
using namespace lldb_private;
@@ -54,6 +59,7 @@ static ScriptInterpreter::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue
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;
@@ -61,7 +67,10 @@ static ScriptInterpreter::SWIGPythonScriptKeyword_Process g_swig_run_script_keyw
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 std::string
ReadPythonBacktrace (PyObject* py_backtrace);
@@ -435,19 +444,23 @@ ScriptInterpreterPython::EnterSession (uint16_t on_entry_flags,
if (in == nullptr || out == nullptr || err == nullptr)
m_interpreter.GetDebugger().AdoptTopIOHandlerFilesIfInvalid (in_sp, out_sp, err_sp);
- if (in == nullptr && in_sp && (on_entry_flags & Locker::NoSTDIN) == 0)
- in = in_sp->GetFile().GetStream();
- if (in)
- {
- m_saved_stdin.Reset(sys_module_dict.GetItemForKey("stdin"));
+ m_saved_stdin.Reset();
- PyObject *new_file = PyFile_FromFile (in, (char *) "", (char *) "r", nullptr);
- sys_module_dict.SetItemForKey ("stdin", new_file);
- Py_DECREF (new_file);
+ if ((on_entry_flags & Locker::NoSTDIN) == 0)
+ {
+ // STDIN is enabled
+ if (in == nullptr && in_sp)
+ in = in_sp->GetFile().GetStream();
+ if (in)
+ {
+ 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);
+ sys_module_dict.SetItemForKey ("stdin", new_file);
+ Py_DECREF (new_file);
+ }
}
- else
- m_saved_stdin.Reset();
-
+
if (out == nullptr && out_sp)
out = out_sp->GetFile().GetStream();
if (out)
@@ -594,9 +607,16 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec
// Set output to a temporary file so we can forward the results on to the result object
Pipe pipe;
- if (pipe.Open())
+ Error pipe_result = pipe.CreateNew(false);
+ if (pipe_result.Success())
{
+#if defined(_WIN32)
+ lldb::file_t read_file = pipe.GetReadNativeHandle();
+ pipe.ReleaseReadFileDescriptor();
+ std::unique_ptr<ConnectionGenericFile> conn_ap(new ConnectionGenericFile(read_file, true));
+#else
std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor(pipe.ReleaseReadFileDescriptor(), true));
+#endif
if (conn_ap->IsConnected())
{
output_comm.SetConnection(conn_ap.release());
@@ -632,7 +652,8 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock |
ScriptInterpreterPython::Locker::InitSession |
- (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0),
+ (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0) |
+ ((result && result->GetInteractive()) ? 0: Locker::NoSTDIN),
ScriptInterpreterPython::Locker::FreeAcquiredLock |
ScriptInterpreterPython::Locker::TearDownSession,
in_file,
@@ -708,7 +729,7 @@ public:
IOHandlerPythonInterpreter (Debugger &debugger,
ScriptInterpreterPython *python) :
- IOHandler (debugger),
+ IOHandler (debugger, IOHandler::Type::PythonInterpreter),
m_python(python)
{
@@ -1617,6 +1638,87 @@ ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP
}
lldb::ScriptInterpreterObjectSP
+ScriptInterpreterPython::CreateScriptedThreadPlan (const char *class_name,
+ lldb::ThreadPlanSP thread_plan_sp)
+{
+ if (class_name == nullptr || class_name[0] == '\0')
+ return lldb::ScriptInterpreterObjectSP();
+
+ if (!thread_plan_sp.get())
+ return lldb::ScriptInterpreterObjectSP();
+
+ 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();
+
+ void* ret_val;
+
+ {
+ Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+
+ ret_val = g_swig_thread_plan_script (class_name,
+ python_interpreter->m_dictionary_name.c_str(),
+ thread_plan_sp);
+ }
+
+ return MakeScriptObject(ret_val);
+}
+
+bool
+ScriptInterpreterPython::ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp,
+ Event *event,
+ bool &script_error)
+{
+ bool explains_stop = true;
+ if (implementor_sp)
+ {
+ 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);
+ if (script_error)
+ return true;
+ }
+ return explains_stop;
+}
+
+bool
+ScriptInterpreterPython::ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp,
+ Event *event,
+ bool &script_error)
+{
+ bool should_stop = true;
+ if (implementor_sp)
+ {
+ 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);
+ if (script_error)
+ return true;
+ }
+ return should_stop;
+}
+
+lldb::StateType
+ScriptInterpreterPython::ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp,
+ bool &script_error)
+{
+ bool should_step = false;
+ if (implementor_sp)
+ {
+ 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);
+ if (script_error)
+ should_step = true;
+ }
+ if (should_step)
+ return lldb::eStateStepping;
+ else
+ return lldb::eStateRunning;
+}
+
+
+lldb::ScriptInterpreterObjectSP
ScriptInterpreterPython::LoadPluginModule (const FileSpec& file_spec,
lldb_private::Error& error)
{
@@ -1759,6 +1861,7 @@ bool
ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name,
lldb::ValueObjectSP valobj,
lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
+ const TypeSummaryOptions& options,
std::string& retval)
{
@@ -1780,11 +1883,14 @@ ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name,
{
Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
{
+ TypeSummaryOptionsSP options_sp(new TypeSummaryOptions(options));
+
Timer scoped_timer ("g_swig_typescript_callback","g_swig_typescript_callback");
ret_val = g_swig_typescript_callback (python_function_name,
GetSessionDictionary().get(),
valobj,
&new_callee,
+ options_sp,
retval);
}
}
@@ -2056,6 +2162,42 @@ ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance (const lldb::Scr
return ret_val;
}
+lldb::ValueObjectSP
+ScriptInterpreterPython::GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor_sp)
+{
+ lldb::ValueObjectSP ret_val(nullptr);
+
+ if (!implementor_sp)
+ return ret_val;
+
+ void* implementor = implementor_sp->GetObject();
+
+ if (!implementor)
+ return ret_val;
+
+ if (!g_swig_getvalue_provider || !g_swig_cast_to_sbvalue || !g_swig_get_valobj_sp_from_sbvalue)
+ return ret_val;
+
+ {
+ Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+ void* child_ptr = g_swig_getvalue_provider (implementor);
+ if (child_ptr != nullptr && child_ptr != Py_None)
+ {
+ lldb::SBValue* sb_value_ptr = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr);
+ if (sb_value_ptr == nullptr)
+ Py_XDECREF(child_ptr);
+ else
+ ret_val = g_swig_get_valobj_sp_from_sbvalue (sb_value_ptr);
+ }
+ else
+ {
+ Py_XDECREF(child_ptr);
+ }
+ }
+
+ return ret_val;
+}
+
static std::string
ReadPythonBacktrace (PyObject* py_backtrace)
{
@@ -2240,6 +2382,38 @@ ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function,
}
return ret_val;
}
+
+bool
+ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function,
+ ValueObject *value,
+ std::string& output,
+ Error& error)
+{
+ bool ret_val;
+ if (!value)
+ {
+ error.SetErrorString("no value");
+ return false;
+ }
+ if (!impl_function || !impl_function[0])
+ {
+ error.SetErrorString("no function to execute");
+ return false;
+ }
+ if (!g_swig_run_script_keyword_value)
+ {
+ error.SetErrorString("internal helper function missing");
+ return false;
+ }
+ {
+ ValueObjectSP value_sp(value->GetSP());
+ Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+ ret_val = g_swig_run_script_keyword_value (impl_function, m_dictionary_name.c_str(), value_sp, output);
+ if (!ret_val)
+ error.SetErrorString("python script evaluation failed");
+ }
+ return ret_val;
+}
uint64_t replace_all(std::string& str, const std::string& oldStr, const std::string& newStr)
{
@@ -2426,7 +2600,8 @@ ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function,
const char* args,
ScriptedCommandSynchronicity synchronicity,
lldb_private::CommandReturnObject& cmd_retobj,
- Error& error)
+ Error& error,
+ const lldb_private::ExecutionContext& exe_ctx)
{
if (!impl_function)
{
@@ -2441,6 +2616,7 @@ ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function,
}
lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this();
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx));
if (!debugger_sp.get())
{
@@ -2464,7 +2640,8 @@ ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function,
m_dictionary_name.c_str(),
debugger_sp,
args,
- cmd_retobj);
+ cmd_retobj,
+ exe_ctx_ref_sp);
}
if (!ret_val)
@@ -2529,6 +2706,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb
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,
@@ -2536,7 +2714,10 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb
SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame,
- SWIGPython_GetDynamicSetting swig_plugin_get)
+ SWIGPythonScriptKeyword_Value swig_run_script_keyword_value,
+ SWIGPython_GetDynamicSetting swig_plugin_get,
+ SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script,
+ SWIGPythonCallThreadPlan swig_call_thread_plan)
{
g_swig_init_callback = swig_init_callback;
g_swig_breakpoint_callback = swig_breakpoint_callback;
@@ -2550,6 +2731,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb
g_swig_get_valobj_sp_from_sbvalue = swig_get_valobj_sp_from_sbvalue;
g_swig_update_provider = swig_update_provider;
g_swig_mighthavechildren_provider = swig_mighthavechildren_provider;
+ g_swig_getvalue_provider = swig_getvalue_provider;
g_swig_call_command = swig_call_command;
g_swig_call_module_init = swig_call_module_init;
g_swig_create_os_plugin = swig_create_os_plugin;
@@ -2557,7 +2739,10 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb
g_swig_run_script_keyword_thread = swig_run_script_keyword_thread;
g_swig_run_script_keyword_target = swig_run_script_keyword_target;
g_swig_run_script_keyword_frame = swig_run_script_keyword_frame;
+ g_swig_run_script_keyword_value = swig_run_script_keyword_value;
g_swig_plugin_get = swig_plugin_get;
+ g_swig_thread_plan_script = swig_thread_plan_script;
+ g_swig_call_thread_plan = swig_call_thread_plan;
}
void
diff --git a/source/Interpreter/embedded_interpreter.py b/source/Interpreter/embedded_interpreter.py
index 51a971690d67..10186f5a9d50 100644
--- a/source/Interpreter/embedded_interpreter.py
+++ b/source/Interpreter/embedded_interpreter.py
@@ -61,7 +61,7 @@ def get_terminal_size(fd):
def readfunc_stdio(prompt):
sys.stdout.write(prompt)
- return sys.stdin.readline()
+ return sys.stdin.readline().rstrip()
def run_python_interpreter (local_dict):
# Pass in the dictionary, for continuity from one session to the next.
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
index a9f8f3b668dc..5073b13f09ab 100644
--- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
+++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
@@ -801,6 +801,36 @@ ABIMacOSX_arm::RegisterIsVolatile (const RegisterInfo *reg_info)
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;
}
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
index 6f7b339e28a2..eee43943d73a 100644
--- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
+++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
@@ -53,13 +53,7 @@ public:
virtual bool
RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info);
-
- virtual bool
- StackUsesFrames ()
- {
- return true;
- }
-
+
virtual bool
CallFrameAddressIsValid (lldb::addr_t cfa)
{
@@ -88,12 +82,6 @@ public:
return pc & ~(lldb::addr_t)1;
}
- virtual bool
- FunctionCallsChangeCFA ()
- {
- return false;
- }
-
virtual const lldb_private::RegisterInfo *
GetRegisterInfoArray (uint32_t &count);
diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
index 8f7962d095fc..465257db31d8 100644
--- a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
+++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
@@ -440,11 +440,11 @@ ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueO
}
const uint32_t type_flags = return_value_type.GetTypeInfo (NULL);
- if (type_flags & ClangASTType::eTypeIsScalar ||
- type_flags & ClangASTType::eTypeIsPointer)
+ if (type_flags & eTypeIsScalar ||
+ type_flags & eTypeIsPointer)
{
- if (type_flags & ClangASTType::eTypeIsInteger ||
- type_flags & ClangASTType::eTypeIsPointer )
+ if (type_flags & eTypeIsInteger ||
+ type_flags & eTypeIsPointer )
{
// Extract the register context so we can read arguments from registers
lldb::offset_t offset = 0;
@@ -477,9 +477,9 @@ ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueO
error.SetErrorString("We don't support returning longer than 128 bit integer values at present.");
}
}
- else if (type_flags & ClangASTType::eTypeIsFloat)
+ else if (type_flags & eTypeIsFloat)
{
- if (type_flags & ClangASTType::eTypeIsComplex)
+ if (type_flags & eTypeIsComplex)
{
// Don't handle complex yet.
error.SetErrorString ("returning complex float values are not supported");
@@ -519,7 +519,7 @@ ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueO
}
}
}
- else if (type_flags & ClangASTType::eTypeIsVector)
+ else if (type_flags & eTypeIsVector)
{
if (byte_size > 0)
{
@@ -874,14 +874,14 @@ ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_
const size_t byte_size = return_clang_type.GetByteSize();
const uint32_t type_flags = return_clang_type.GetTypeInfo (NULL);
- if (type_flags & ClangASTType::eTypeIsScalar ||
- type_flags & ClangASTType::eTypeIsPointer)
+ if (type_flags & eTypeIsScalar ||
+ type_flags & eTypeIsPointer)
{
value.SetValueType(Value::eValueTypeScalar);
bool success = false;
- if (type_flags & ClangASTType::eTypeIsInteger ||
- type_flags & ClangASTType::eTypeIsPointer )
+ if (type_flags & eTypeIsInteger ||
+ type_flags & eTypeIsPointer )
{
// Extract the register context so we can read arguments from registers
if (byte_size <= 8)
@@ -890,7 +890,7 @@ ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_
if (x0_reg_info)
{
uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, 0);
- const bool is_signed = (type_flags & ClangASTType::eTypeIsSigned) != 0;
+ const bool is_signed = (type_flags & eTypeIsSigned) != 0;
switch (byte_size)
{
default:
@@ -965,9 +965,9 @@ ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_
}
}
}
- else if (type_flags & ClangASTType::eTypeIsFloat)
+ else if (type_flags & eTypeIsFloat)
{
- if (type_flags & ClangASTType::eTypeIsComplex)
+ if (type_flags & eTypeIsComplex)
{
// Don't handle complex yet.
}
@@ -1010,7 +1010,7 @@ ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_
ConstString(""));
}
- else if (type_flags & ClangASTType::eTypeIsVector)
+ else if (type_flags & eTypeIsVector)
{
if (byte_size > 0)
{
@@ -1046,8 +1046,8 @@ ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_
}
}
}
- else if (type_flags & ClangASTType::eTypeIsStructUnion ||
- type_flags & ClangASTType::eTypeIsClass)
+ else if (type_flags & eTypeIsStructUnion ||
+ type_flags & eTypeIsClass)
{
DataExtractor data;
diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h
index 0753b23ce2a2..6cce6a6f1174 100644
--- a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h
+++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h
@@ -46,15 +46,7 @@ public:
virtual bool
RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info);
-
-
- virtual bool
- StackUsesFrames ()
- {
- // MacOSX uses frame pointers.
- return true;
- }
-
+
// The arm64 ABI requires that stack frames be 16 byte aligned.
// When there is a trap handler on the stack, e.g. _sigtramp in userland
// code, we've seen that the stack pointer is often not aligned properly
@@ -87,12 +79,6 @@ public:
return true;
}
- virtual bool
- FunctionCallsChangeCFA ()
- {
- return false;
- }
-
virtual const lldb_private::RegisterInfo *
GetRegisterInfoArray (uint32_t &count);
diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
index 43784a5c9111..d81b7a7e684b 100644
--- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
+++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
@@ -64,13 +64,7 @@ public:
virtual bool
RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info);
-
- virtual bool
- StackUsesFrames ()
- {
- return true;
- }
-
+
// The Darwin 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
@@ -102,12 +96,6 @@ public:
return pc <= UINT32_MAX;
}
- virtual bool
- FunctionCallsChangeCFA ()
- {
- return true;
- }
-
virtual const lldb_private::RegisterInfo *
GetRegisterInfoArray (uint32_t &count);
diff --git a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h
index 989c4a16710a..1550a38c4f3b 100644
--- a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h
+++ b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h
@@ -75,13 +75,7 @@ public:
virtual bool
RegisterIsVolatile ( const lldb_private::RegisterInfo *reg_info );
-
- virtual bool
- StackUsesFrames ( void )
- {
- return true;
- }
-
+
virtual bool
CallFrameAddressIsValid ( lldb::addr_t cfa )
{
@@ -101,12 +95,6 @@ public:
return true;
}
- virtual bool
- FunctionCallsChangeCFA ( void )
- {
- return true;
- }
-
virtual const lldb_private::RegisterInfo *
GetRegisterInfoArray ( uint32_t &count );
diff --git a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp
new file mode 100644
index 000000000000..adb3313d1a30
--- /dev/null
+++ b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp
@@ -0,0 +1,1120 @@
+//===-- ABISysV_ppc.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_ppc.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_f0,
+ gcc_dwarf_f1,
+ gcc_dwarf_f2,
+ gcc_dwarf_f3,
+ gcc_dwarf_f4,
+ gcc_dwarf_f5,
+ gcc_dwarf_f6,
+ gcc_dwarf_f7,
+ gcc_dwarf_f8,
+ gcc_dwarf_f9,
+ gcc_dwarf_f10,
+ gcc_dwarf_f11,
+ gcc_dwarf_f12,
+ gcc_dwarf_f13,
+ gcc_dwarf_f14,
+ gcc_dwarf_f15,
+ gcc_dwarf_f16,
+ gcc_dwarf_f17,
+ gcc_dwarf_f18,
+ gcc_dwarf_f19,
+ gcc_dwarf_f20,
+ gcc_dwarf_f21,
+ gcc_dwarf_f22,
+ gcc_dwarf_f23,
+ gcc_dwarf_f24,
+ gcc_dwarf_f25,
+ gcc_dwarf_f26,
+ gcc_dwarf_f27,
+ gcc_dwarf_f28,
+ gcc_dwarf_f29,
+ gcc_dwarf_f30,
+ gcc_dwarf_f31,
+ gcc_dwarf_cr,
+ gcc_dwarf_fpscr,
+ gcc_dwarf_xer = 101,
+ gcc_dwarf_lr = 108,
+ gcc_dwarf_ctr,
+ gcc_dwarf_pc,
+ gcc_dwarf_cfa,
+};
+
+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_lr,
+ gdb_cr,
+ gdb_xer,
+ gdb_ctr,
+ gdb_pc,
+};
+
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, 8, 0, eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4}, NULL, NULL }
+static const RegisterInfo
+g_register_infos[] =
+{
+ // General purpose registers. GCC, DWARF, Generic, GDB
+ DEFINE_GPR(r0, NULL, gcc_dwarf_r0, gcc_dwarf_r0, LLDB_INVALID_REGNUM, gdb_r0),
+ DEFINE_GPR(r1, "sp", gcc_dwarf_r1, gcc_dwarf_r1, LLDB_REGNUM_GENERIC_SP, gdb_r1),
+ DEFINE_GPR(r2, NULL, gcc_dwarf_r2, gcc_dwarf_r2, LLDB_INVALID_REGNUM, gdb_r2),
+ DEFINE_GPR(r3, "arg1",gcc_dwarf_r3, gcc_dwarf_r3, LLDB_REGNUM_GENERIC_ARG1, gdb_r3),
+ DEFINE_GPR(r4, "arg2",gcc_dwarf_r4, gcc_dwarf_r4, LLDB_REGNUM_GENERIC_ARG2 ,gdb_r4),
+ DEFINE_GPR(r5, "arg3",gcc_dwarf_r5, gcc_dwarf_r5, LLDB_REGNUM_GENERIC_ARG3, gdb_r5),
+ DEFINE_GPR(r6, "arg4",gcc_dwarf_r6, gcc_dwarf_r6, LLDB_REGNUM_GENERIC_ARG4, gdb_r6),
+ DEFINE_GPR(r7, "arg5",gcc_dwarf_r7, gcc_dwarf_r7, LLDB_REGNUM_GENERIC_ARG5, gdb_r7),
+ DEFINE_GPR(r8, "arg6",gcc_dwarf_r8, gcc_dwarf_r8, LLDB_REGNUM_GENERIC_ARG6, gdb_r8),
+ DEFINE_GPR(r9, "arg7",gcc_dwarf_r9, gcc_dwarf_r9, LLDB_REGNUM_GENERIC_ARG7, gdb_r9),
+ DEFINE_GPR(r10, "arg8",gcc_dwarf_r10, gcc_dwarf_r10, LLDB_REGNUM_GENERIC_ARG8, gdb_r10),
+ DEFINE_GPR(r11, NULL, gcc_dwarf_r11, gcc_dwarf_r11, LLDB_INVALID_REGNUM, gdb_r11),
+ DEFINE_GPR(r12, NULL, gcc_dwarf_r12, gcc_dwarf_r12, LLDB_INVALID_REGNUM, gdb_r12),
+ DEFINE_GPR(r13, NULL, gcc_dwarf_r13, gcc_dwarf_r13, LLDB_INVALID_REGNUM, gdb_r13),
+ DEFINE_GPR(r14, NULL, gcc_dwarf_r14, gcc_dwarf_r14, LLDB_INVALID_REGNUM, gdb_r14),
+ DEFINE_GPR(r15, NULL, gcc_dwarf_r15, gcc_dwarf_r15, LLDB_INVALID_REGNUM, gdb_r15),
+ DEFINE_GPR(r16, NULL, gcc_dwarf_r16, gcc_dwarf_r16, LLDB_INVALID_REGNUM, gdb_r16),
+ DEFINE_GPR(r17, NULL, gcc_dwarf_r17, gcc_dwarf_r17, LLDB_INVALID_REGNUM, gdb_r17),
+ DEFINE_GPR(r18, NULL, gcc_dwarf_r18, gcc_dwarf_r18, LLDB_INVALID_REGNUM, gdb_r18),
+ DEFINE_GPR(r19, NULL, gcc_dwarf_r19, gcc_dwarf_r19, LLDB_INVALID_REGNUM, gdb_r19),
+ DEFINE_GPR(r20, NULL, gcc_dwarf_r20, gcc_dwarf_r20, LLDB_INVALID_REGNUM, gdb_r20),
+ DEFINE_GPR(r21, NULL, gcc_dwarf_r21, gcc_dwarf_r21, LLDB_INVALID_REGNUM, gdb_r21),
+ DEFINE_GPR(r22, NULL, gcc_dwarf_r22, gcc_dwarf_r22, LLDB_INVALID_REGNUM, gdb_r22),
+ DEFINE_GPR(r23, NULL, gcc_dwarf_r23, gcc_dwarf_r23, LLDB_INVALID_REGNUM, gdb_r23),
+ DEFINE_GPR(r24, NULL, gcc_dwarf_r24, gcc_dwarf_r24, LLDB_INVALID_REGNUM, gdb_r24),
+ DEFINE_GPR(r25, NULL, gcc_dwarf_r25, gcc_dwarf_r25, LLDB_INVALID_REGNUM, gdb_r25),
+ DEFINE_GPR(r26, NULL, gcc_dwarf_r26, gcc_dwarf_r26, LLDB_INVALID_REGNUM, gdb_r26),
+ DEFINE_GPR(r27, NULL, gcc_dwarf_r27, gcc_dwarf_r27, LLDB_INVALID_REGNUM, gdb_r27),
+ DEFINE_GPR(r28, NULL, gcc_dwarf_r28, gcc_dwarf_r28, LLDB_INVALID_REGNUM, gdb_r28),
+ DEFINE_GPR(r29, NULL, gcc_dwarf_r29, gcc_dwarf_r29, LLDB_INVALID_REGNUM, gdb_r29),
+ DEFINE_GPR(r30, NULL, gcc_dwarf_r30, gcc_dwarf_r30, LLDB_INVALID_REGNUM, gdb_r30),
+ DEFINE_GPR(r31, NULL, gcc_dwarf_r31, gcc_dwarf_r31, LLDB_INVALID_REGNUM, gdb_r31),
+ DEFINE_GPR(lr, "lr", gcc_dwarf_lr, gcc_dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_lr),
+ DEFINE_GPR(cr, "cr", gcc_dwarf_cr, gcc_dwarf_cr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(xer, "xer", gcc_dwarf_xer, gcc_dwarf_xer, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ctr, "ctr", gcc_dwarf_ctr, gcc_dwarf_ctr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(pc, "pc", gcc_dwarf_pc, gcc_dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ { NULL, NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_cfa, gcc_dwarf_cfa, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, NULL, NULL},
+};
+
+static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
+
+const lldb_private::RegisterInfo *
+ABISysV_ppc::GetRegisterInfoArray (uint32_t &count)
+{
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+
+size_t
+ABISysV_ppc::GetRedZoneSize () const
+{
+ return 224;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABISysV_ppc::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ if (arch.GetTriple().getArch() == llvm::Triple::ppc)
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABISysV_ppc);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABISysV_ppc::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_ppc::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
+
+ sp -= 8;
+
+ 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);
+ ProcessSP process_sp (thread.GetProcess());
+
+ RegisterValue reg_value;
+
+#if 0
+ // This code adds an extra frame so that we don't lose the function that we came from
+ // by pushing the PC and the FP and then writing the current FP to point to the FP value
+ // we just pushed. It is disabled for now until the stack backtracing code can be debugged.
+
+ // Save current PC
+ const RegisterInfo *fp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ if (reg_ctx->ReadRegister(pc_reg_info, reg_value))
+ {
+ if (log)
+ log->Printf("Pushing the current PC onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64());
+
+ if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error))
+ return false;
+
+ sp -= 8;
+
+ // Save current FP
+ if (reg_ctx->ReadRegister(fp_reg_info, reg_value))
+ {
+ if (log)
+ log->Printf("Pushing the current FP onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64());
+
+ if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error))
+ return false;
+ }
+ // Setup FP backchain
+ reg_value.SetUInt64 (sp);
+
+ if (log)
+ log->Printf("Writing FP: 0x%" PRIx64 " (for FP backchain)", reg_value.GetAsUInt64());
+
+ if (!reg_ctx->WriteRegister(fp_reg_info, reg_value))
+ {
+ return false;
+ }
+
+ sp -= 8;
+ }
+#endif
+
+ if (log)
+ log->Printf("Pushing the return address onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, (uint64_t)return_addr);
+
+ // Save return address onto the stack
+ if (!process_sp->WritePointerToMemory(sp, return_addr, error))
+ return false;
+
+ // %r1 is set to the actual stack value.
+
+ if (log)
+ log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_info, sp))
+ return false;
+
+ // %pc is set to the address of the called function.
+
+ if (log)
+ log->Printf("Writing IP: 0x%" PRIx64, (uint64_t)func_addr);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr))
+ return false;
+
+ return true;
+}
+
+static bool ReadIntegerArgument(Scalar &scalar,
+ unsigned int bit_width,
+ bool is_signed,
+ Thread &thread,
+ uint32_t *argument_register_ids,
+ unsigned int &current_argument_register,
+ addr_t &current_stack_argument)
+{
+ if (bit_width > 64)
+ return false; // Scalar can't hold large integer arguments
+
+ if (current_argument_register < 6)
+ {
+ scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned(argument_register_ids[current_argument_register], 0);
+ current_argument_register++;
+ if (is_signed)
+ scalar.SignExtend (bit_width);
+ }
+ else
+ {
+ uint32_t byte_size = (bit_width + (8-1))/8;
+ Error error;
+ if (thread.GetProcess()->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, is_signed, scalar, error))
+ {
+ current_stack_argument += byte_size;
+ return true;
+ }
+ return false;
+ }
+ return true;
+}
+
+bool
+ABISysV_ppc::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ // Extract the register context so we can read arguments from registers
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ addr_t sp = reg_ctx->GetSP(0);
+
+ if (!sp)
+ return false;
+
+ addr_t current_stack_argument = sp + 48; // jump over return address
+
+ uint32_t argument_register_ids[8];
+
+ argument_register_ids[0] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1)->kinds[eRegisterKindLLDB];
+ argument_register_ids[1] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2)->kinds[eRegisterKindLLDB];
+ argument_register_ids[2] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG3)->kinds[eRegisterKindLLDB];
+ argument_register_ids[3] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG4)->kinds[eRegisterKindLLDB];
+ argument_register_ids[4] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG5)->kinds[eRegisterKindLLDB];
+ argument_register_ids[5] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG6)->kinds[eRegisterKindLLDB];
+ argument_register_ids[6] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG7)->kinds[eRegisterKindLLDB];
+ argument_register_ids[7] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG8)->kinds[eRegisterKindLLDB];
+
+ unsigned int current_argument_register = 0;
+
+ for (value_index = 0;
+ value_index < num_values;
+ ++value_index)
+ {
+ Value *value = values.GetValueAtIndex(value_index);
+
+ if (!value)
+ return false;
+
+ // We currently only support extracting values with Clang QualTypes.
+ // Do we care about others?
+ ClangASTType clang_type = value->GetClangType();
+ if (!clang_type)
+ return false;
+ bool is_signed;
+
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(),
+ is_signed,
+ thread,
+ argument_register_ids,
+ current_argument_register,
+ current_stack_argument);
+ }
+ else if (clang_type.IsPointerType ())
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(),
+ false,
+ thread,
+ argument_register_ids,
+ current_argument_register,
+ current_stack_argument);
+ }
+ }
+
+ return true;
+}
+
+Error
+ABISysV_ppc::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())
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0);
+
+ 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)
+ {
+ uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (reg_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
+ {
+ size_t bit_width = clang_type.GetBitSize();
+ if (bit_width <= 64)
+ {
+ 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;
+ }
+
+ unsigned char buffer[16];
+ ByteOrder byte_order = data.GetByteOrder();
+
+ data.CopyByteOrderedData (0, num_bytes, buffer, 16, byte_order);
+ set_it_simple = true;
+ }
+ else
+ {
+ // FIXME - don't know how to do 80 bit long doubles yet.
+ error.SetErrorString ("We don't support returning float values > 64 bits at present");
+ }
+ }
+ }
+
+ if (!set_it_simple)
+ {
+ // Okay we've got a structure or something that doesn't fit in a simple register.
+ // We should figure out where it really goes, but we don't support this yet.
+ error.SetErrorString ("We only support setting simple integer and float return types at present.");
+ }
+
+ return error;
+}
+
+
+ValueObjectSP
+ABISysV_ppc::GetReturnValueObjectSimple (Thread &thread,
+ ClangASTType &return_clang_type) const
+{
+ ValueObjectSP return_valobj_sp;
+ Value value;
+
+ if (!return_clang_type)
+ return return_valobj_sp;
+
+ //value.SetContext (Value::eContextTypeClangType, return_value_type);
+ 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 ();
+ 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
+
+ const size_t byte_size = return_clang_type.GetByteSize();
+ uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("r3", 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;
+ }
+ }
+ else if (type_flags & eTypeIsFloat)
+ {
+ if (type_flags & eTypeIsComplex)
+ {
+ // Don't handle complex yet.
+ }
+ else
+ {
+ const size_t byte_size = return_clang_type.GetByteSize();
+ if (byte_size <= sizeof(long double))
+ {
+ const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0);
+ RegisterValue f1_value;
+ if (reg_ctx->ReadRegister (f1_info, f1_value))
+ {
+ DataExtractor data;
+ if (f1_value.GetData(data))
+ {
+ lldb::offset_t offset = 0;
+ if (byte_size == sizeof(float))
+ {
+ value.GetScalar() = (float) data.GetFloat(&offset);
+ success = true;
+ }
+ else if (byte_size == sizeof(double))
+ {
+ value.GetScalar() = (double) data.GetDouble(&offset);
+ success = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success)
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+
+ }
+ else if (type_flags & eTypeIsPointer)
+ {
+ unsigned r3_id = reg_ctx->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB];
+ value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0);
+ value.SetValueType(Value::eValueTypeScalar);
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ }
+ else if (type_flags & eTypeIsVector)
+ {
+ const size_t byte_size = return_clang_type.GetByteSize();
+ if (byte_size > 0)
+ {
+
+ const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v0", 0);
+ if (altivec_reg == NULL)
+ altivec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0);
+ if (altivec_reg)
+ {
+ if (byte_size <= altivec_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(altivec_reg, reg_value))
+ {
+ Error error;
+ if (reg_value.GetAsMemoryData (altivec_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);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return return_valobj_sp;
+}
+
+ValueObjectSP
+ABISysV_ppc::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;
+
+ const size_t bit_width = return_clang_type.GetBitSize();
+ if (return_clang_type.IsAggregateType())
+ {
+ Target *target = exe_ctx.GetTargetPtr();
+ bool is_memory = true;
+ if (bit_width <= 128)
+ {
+ ByteOrder target_byte_order = target->GetArchitecture().GetByteOrder();
+ DataBufferSP data_sp (new DataBufferHeap(16, 0));
+ DataExtractor return_ext (data_sp,
+ target_byte_order,
+ target->GetArchitecture().GetAddressByteSize());
+
+ const RegisterInfo *r3_info = reg_ctx_sp->GetRegisterInfoByName("r3", 0);
+ const RegisterInfo *rdx_info = reg_ctx_sp->GetRegisterInfoByName("rdx", 0);
+
+ RegisterValue r3_value, rdx_value;
+ reg_ctx_sp->ReadRegister (r3_info, r3_value);
+ reg_ctx_sp->ReadRegister (rdx_info, rdx_value);
+
+ DataExtractor r3_data, rdx_data;
+
+ r3_value.GetData(r3_data);
+ rdx_value.GetData(rdx_data);
+
+ uint32_t fp_bytes = 0; // Tracks how much of the xmm registers we've consumed so far
+ uint32_t integer_bytes = 0; // Tracks how much of the r3/rds registers we've consumed so far
+
+ const uint32_t num_children = return_clang_type.GetNumFields ();
+
+ // Since we are in the small struct regime, assume we are not in memory.
+ is_memory = false;
+
+ for (uint32_t idx = 0; idx < num_children; idx++)
+ {
+ std::string name;
+ uint64_t field_bit_offset = 0;
+ bool is_signed;
+ bool is_complex;
+ 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();
+
+ // If there are any unaligned fields, this is stored in memory.
+ if (field_bit_offset % field_bit_width != 0)
+ {
+ is_memory = true;
+ break;
+ }
+
+ uint32_t field_byte_width = field_bit_width/8;
+ uint32_t field_byte_offset = field_bit_offset/8;
+
+
+ DataExtractor *copy_from_extractor = NULL;
+ uint32_t copy_from_offset = 0;
+
+ if (field_clang_type.IsIntegerType (is_signed) || field_clang_type.IsPointerType ())
+ {
+ if (integer_bytes < 8)
+ {
+ if (integer_bytes + field_byte_width <= 8)
+ {
+ // This is in RAX, copy from register to our result structure:
+ copy_from_extractor = &r3_data;
+ copy_from_offset = integer_bytes;
+ integer_bytes += field_byte_width;
+ }
+ else
+ {
+ // The next field wouldn't fit in the remaining space, so we pushed it to rdx.
+ copy_from_extractor = &rdx_data;
+ copy_from_offset = 0;
+ integer_bytes = 8 + field_byte_width;
+
+ }
+ }
+ else if (integer_bytes + field_byte_width <= 16)
+ {
+ copy_from_extractor = &rdx_data;
+ copy_from_offset = integer_bytes - 8;
+ integer_bytes += field_byte_width;
+ }
+ else
+ {
+ // The last field didn't fit. I can't see how that would happen w/o the overall size being
+ // greater than 16 bytes. For now, return a NULL return value object.
+ return return_valobj_sp;
+ }
+ }
+ else if (field_clang_type.IsFloatingPointType (count, is_complex))
+ {
+ // Structs with long doubles are always passed in memory.
+ if (field_bit_width == 128)
+ {
+ is_memory = true;
+ break;
+ }
+ else if (field_bit_width == 64)
+ {
+ copy_from_offset = 0;
+ fp_bytes += field_byte_width;
+ }
+ else if (field_bit_width == 32)
+ {
+ // This one is kind of complicated. If we are in an "eightbyte" with another float, we'll
+ // be stuffed into an xmm register with it. If we are in an "eightbyte" with one or more ints,
+ // then we will be stuffed into the appropriate GPR with them.
+ bool in_gpr;
+ if (field_byte_offset % 8 == 0)
+ {
+ // We are at the beginning of one of the eightbytes, so check the next element (if any)
+ if (idx == num_children - 1)
+ in_gpr = false;
+ else
+ {
+ uint64_t next_field_bit_offset = 0;
+ ClangASTType next_field_clang_type = return_clang_type.GetFieldAtIndex (idx + 1,
+ name,
+ &next_field_bit_offset,
+ NULL,
+ NULL);
+ if (next_field_clang_type.IsIntegerType (is_signed))
+ in_gpr = true;
+ else
+ {
+ copy_from_offset = 0;
+ in_gpr = false;
+ }
+ }
+
+ }
+ else if (field_byte_offset % 4 == 0)
+ {
+ // We are inside of an eightbyte, so see if the field before us is floating point:
+ // This could happen if somebody put padding in the structure.
+ if (idx == 0)
+ in_gpr = false;
+ else
+ {
+ uint64_t prev_field_bit_offset = 0;
+ ClangASTType prev_field_clang_type = return_clang_type.GetFieldAtIndex (idx - 1,
+ name,
+ &prev_field_bit_offset,
+ NULL,
+ NULL);
+ if (prev_field_clang_type.IsIntegerType (is_signed))
+ in_gpr = true;
+ else
+ {
+ copy_from_offset = 4;
+ in_gpr = false;
+ }
+ }
+
+ }
+ else
+ {
+ is_memory = true;
+ continue;
+ }
+
+ // Okay, we've figured out whether we are in GPR or XMM, now figure out which one.
+ if (in_gpr)
+ {
+ if (integer_bytes < 8)
+ {
+ // This is in RAX, copy from register to our result structure:
+ copy_from_extractor = &r3_data;
+ copy_from_offset = integer_bytes;
+ integer_bytes += field_byte_width;
+ }
+ else
+ {
+ copy_from_extractor = &rdx_data;
+ copy_from_offset = integer_bytes - 8;
+ integer_bytes += field_byte_width;
+ }
+ }
+ else
+ {
+ fp_bytes += field_byte_width;
+ }
+ }
+ }
+
+ // These two tests are just sanity checks. If I somehow get the
+ // type calculation wrong above it is better to just return nothing
+ // than to assert or crash.
+ if (!copy_from_extractor)
+ return return_valobj_sp;
+ if (copy_from_offset + field_byte_width > copy_from_extractor->GetByteSize())
+ return return_valobj_sp;
+
+ copy_from_extractor->CopyByteOrderedData (copy_from_offset,
+ field_byte_width,
+ data_sp->GetBytes() + field_byte_offset,
+ field_byte_width,
+ target_byte_order);
+ }
+
+ if (!is_memory)
+ {
+ // The result is in our data buffer. Let's make a variable object out of it:
+ return_valobj_sp = ValueObjectConstResult::Create (&thread,
+ return_clang_type,
+ ConstString(""),
+ return_ext);
+ }
+ }
+
+
+ // FIXME: This is just taking a guess, r3 may very well no longer hold the return storage location.
+ // If we are going to do this right, when we make a new frame we should check to see if it uses a memory
+ // return, and if we are at the first instruction and if so stash away the return location. Then we would
+ // only return the memory return value if we know it is valid.
+
+ if (is_memory)
+ {
+ unsigned r3_id = reg_ctx_sp->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB];
+ lldb::addr_t storage_addr = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0);
+ return_valobj_sp = ValueObjectMemory::Create (&thread,
+ "",
+ Address (storage_addr, NULL),
+ return_clang_type);
+ }
+ }
+
+ return return_valobj_sp;
+}
+
+bool
+ABISysV_ppc::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ uint32_t lr_reg_num = gcc_dwarf_lr;
+ uint32_t sp_reg_num = gcc_dwarf_r1;
+ uint32_t pc_reg_num = gcc_dwarf_pc;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ // Our Call Frame Address is the stack pointer value
+ row->SetCFARegister (sp_reg_num);
+
+ // 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 ("ppc at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+
+ return true;
+}
+
+bool
+ABISysV_ppc::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ uint32_t sp_reg_num = gcc_dwarf_r1;
+ uint32_t pc_reg_num = gcc_dwarf_lr;
+
+ 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->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 1, true);
+ row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("ppc default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ unwind_plan.SetReturnAddressRegister(gcc_dwarf_lr);
+ return true;
+}
+
+bool
+ABISysV_ppc::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ return !RegisterIsCalleeSaved (reg_info);
+}
+
+
+
+// See "Register Usage" in the
+// "System V Application Binary Interface"
+// "64-bit PowerPC ELF Application Binary Interface Supplement"
+// current version is 1.9 released 2004 at http://refspecs.linuxfoundation.org/ELF/ppc/PPC-elf64abi-1.9.pdf
+
+bool
+ABISysV_ppc::RegisterIsCalleeSaved (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ // Preserved registers are :
+ // r1,r2,r13-r31
+ // f14-f31 (not yet)
+ // v20-v31 (not yet)
+ // vrsave (not yet)
+
+ const char *name = reg_info->name;
+ if (name[0] == 'r')
+ {
+ if ((name[1] == '1' || name[1] == '2') && name[2] == '\0')
+ return true;
+ if (name[1] == '1' && name[2] > '2')
+ return true;
+ if ((name[1] == '2' || name[1] == '3') && name[2] != '\0')
+ return true;
+ }
+
+ if (name[0] == 'f' && name[1] >= '0' && name[1] <= '9')
+ {
+ if (name[3] == '1' && name[4] >= '4')
+ return true;
+ if ((name[3] == '2' || name[3] == '3') && name[4] != '\0')
+ return true;
+ }
+
+ 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_ppc::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "System V ABI for ppc targets",
+ CreateInstance);
+}
+
+void
+ABISysV_ppc::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABISysV_ppc::GetPluginNameStatic()
+{
+ static ConstString g_name("sysv-ppc");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABISysV_ppc::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABISysV_ppc::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h
new file mode 100644
index 000000000000..a7aad300e297
--- /dev/null
+++ b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h
@@ -0,0 +1,143 @@
+//===-- ABISysV_ppc.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_ppc_h_
+#define liblldb_ABISysV_ppc_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABISysV_ppc :
+ public lldb_private::ABI
+{
+public:
+
+ ~ABISysV_ppc()
+ {
+ }
+
+ 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
+ StackUsesFrames ()
+ {
+ return true;
+ }
+
+ // The SysV ppc 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)
+ {
+ // We have a 64 bit address space, so anything is valid as opcodes
+ // aren't fixed width...
+ return true;
+ }
+
+ virtual bool
+ FunctionCallsChangeCFA ()
+ {
+ 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_ppc() : lldb_private::ABI() { } // Call CreateInstance instead.
+};
+
+#endif // liblldb_ABI_h_
diff --git a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp
new file mode 100644
index 000000000000..46f1e1023f0a
--- /dev/null
+++ b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp
@@ -0,0 +1,1124 @@
+//===-- ABISysV_ppc64.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_ppc64.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_f0,
+ gcc_dwarf_f1,
+ gcc_dwarf_f2,
+ gcc_dwarf_f3,
+ gcc_dwarf_f4,
+ gcc_dwarf_f5,
+ gcc_dwarf_f6,
+ gcc_dwarf_f7,
+ gcc_dwarf_f8,
+ gcc_dwarf_f9,
+ gcc_dwarf_f10,
+ gcc_dwarf_f11,
+ gcc_dwarf_f12,
+ gcc_dwarf_f13,
+ gcc_dwarf_f14,
+ gcc_dwarf_f15,
+ gcc_dwarf_f16,
+ gcc_dwarf_f17,
+ gcc_dwarf_f18,
+ gcc_dwarf_f19,
+ gcc_dwarf_f20,
+ gcc_dwarf_f21,
+ gcc_dwarf_f22,
+ gcc_dwarf_f23,
+ gcc_dwarf_f24,
+ gcc_dwarf_f25,
+ gcc_dwarf_f26,
+ gcc_dwarf_f27,
+ gcc_dwarf_f28,
+ gcc_dwarf_f29,
+ gcc_dwarf_f30,
+ gcc_dwarf_f31,
+ gcc_dwarf_cr,
+ gcc_dwarf_fpscr,
+ gcc_dwarf_xer = 101,
+ gcc_dwarf_lr = 108,
+ gcc_dwarf_ctr,
+ gcc_dwarf_pc,
+ gcc_dwarf_cfa,
+};
+
+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_lr,
+ gdb_cr,
+ gdb_xer,
+ gdb_ctr,
+ gdb_pc,
+};
+
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, 8, 0, eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4}, NULL, NULL }
+static const RegisterInfo
+g_register_infos[] =
+{
+ // General purpose registers. GCC, DWARF, Generic, GDB
+ DEFINE_GPR(r0, NULL, gcc_dwarf_r0, gcc_dwarf_r0, LLDB_INVALID_REGNUM, gdb_r0),
+ DEFINE_GPR(r1, "sp", gcc_dwarf_r1, gcc_dwarf_r1, LLDB_REGNUM_GENERIC_SP, gdb_r1),
+ DEFINE_GPR(r2, NULL, gcc_dwarf_r2, gcc_dwarf_r2, LLDB_INVALID_REGNUM, gdb_r2),
+ DEFINE_GPR(r3, "arg1",gcc_dwarf_r3, gcc_dwarf_r3, LLDB_REGNUM_GENERIC_ARG1, gdb_r3),
+ DEFINE_GPR(r4, "arg2",gcc_dwarf_r4, gcc_dwarf_r4, LLDB_REGNUM_GENERIC_ARG2 ,gdb_r4),
+ DEFINE_GPR(r5, "arg3",gcc_dwarf_r5, gcc_dwarf_r5, LLDB_REGNUM_GENERIC_ARG3, gdb_r5),
+ DEFINE_GPR(r6, "arg4",gcc_dwarf_r6, gcc_dwarf_r6, LLDB_REGNUM_GENERIC_ARG4, gdb_r6),
+ DEFINE_GPR(r7, "arg5",gcc_dwarf_r7, gcc_dwarf_r7, LLDB_REGNUM_GENERIC_ARG5, gdb_r7),
+ DEFINE_GPR(r8, "arg6",gcc_dwarf_r8, gcc_dwarf_r8, LLDB_REGNUM_GENERIC_ARG6, gdb_r8),
+ DEFINE_GPR(r9, "arg7",gcc_dwarf_r9, gcc_dwarf_r9, LLDB_REGNUM_GENERIC_ARG7, gdb_r9),
+ DEFINE_GPR(r10, "arg8",gcc_dwarf_r10, gcc_dwarf_r10, LLDB_REGNUM_GENERIC_ARG8, gdb_r10),
+ DEFINE_GPR(r11, NULL, gcc_dwarf_r11, gcc_dwarf_r11, LLDB_INVALID_REGNUM, gdb_r11),
+ DEFINE_GPR(r12, NULL, gcc_dwarf_r12, gcc_dwarf_r12, LLDB_INVALID_REGNUM, gdb_r12),
+ DEFINE_GPR(r13, NULL, gcc_dwarf_r13, gcc_dwarf_r13, LLDB_INVALID_REGNUM, gdb_r13),
+ DEFINE_GPR(r14, NULL, gcc_dwarf_r14, gcc_dwarf_r14, LLDB_INVALID_REGNUM, gdb_r14),
+ DEFINE_GPR(r15, NULL, gcc_dwarf_r15, gcc_dwarf_r15, LLDB_INVALID_REGNUM, gdb_r15),
+ DEFINE_GPR(r16, NULL, gcc_dwarf_r16, gcc_dwarf_r16, LLDB_INVALID_REGNUM, gdb_r16),
+ DEFINE_GPR(r17, NULL, gcc_dwarf_r17, gcc_dwarf_r17, LLDB_INVALID_REGNUM, gdb_r17),
+ DEFINE_GPR(r18, NULL, gcc_dwarf_r18, gcc_dwarf_r18, LLDB_INVALID_REGNUM, gdb_r18),
+ DEFINE_GPR(r19, NULL, gcc_dwarf_r19, gcc_dwarf_r19, LLDB_INVALID_REGNUM, gdb_r19),
+ DEFINE_GPR(r20, NULL, gcc_dwarf_r20, gcc_dwarf_r20, LLDB_INVALID_REGNUM, gdb_r20),
+ DEFINE_GPR(r21, NULL, gcc_dwarf_r21, gcc_dwarf_r21, LLDB_INVALID_REGNUM, gdb_r21),
+ DEFINE_GPR(r22, NULL, gcc_dwarf_r22, gcc_dwarf_r22, LLDB_INVALID_REGNUM, gdb_r22),
+ DEFINE_GPR(r23, NULL, gcc_dwarf_r23, gcc_dwarf_r23, LLDB_INVALID_REGNUM, gdb_r23),
+ DEFINE_GPR(r24, NULL, gcc_dwarf_r24, gcc_dwarf_r24, LLDB_INVALID_REGNUM, gdb_r24),
+ DEFINE_GPR(r25, NULL, gcc_dwarf_r25, gcc_dwarf_r25, LLDB_INVALID_REGNUM, gdb_r25),
+ DEFINE_GPR(r26, NULL, gcc_dwarf_r26, gcc_dwarf_r26, LLDB_INVALID_REGNUM, gdb_r26),
+ DEFINE_GPR(r27, NULL, gcc_dwarf_r27, gcc_dwarf_r27, LLDB_INVALID_REGNUM, gdb_r27),
+ DEFINE_GPR(r28, NULL, gcc_dwarf_r28, gcc_dwarf_r28, LLDB_INVALID_REGNUM, gdb_r28),
+ DEFINE_GPR(r29, NULL, gcc_dwarf_r29, gcc_dwarf_r29, LLDB_INVALID_REGNUM, gdb_r29),
+ DEFINE_GPR(r30, NULL, gcc_dwarf_r30, gcc_dwarf_r30, LLDB_INVALID_REGNUM, gdb_r30),
+ DEFINE_GPR(r31, NULL, gcc_dwarf_r31, gcc_dwarf_r31, LLDB_INVALID_REGNUM, gdb_r31),
+ DEFINE_GPR(lr, "lr", gcc_dwarf_lr, gcc_dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_lr),
+ DEFINE_GPR(cr, "cr", gcc_dwarf_cr, gcc_dwarf_cr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(xer, "xer", gcc_dwarf_xer, gcc_dwarf_xer, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ctr, "ctr", gcc_dwarf_ctr, gcc_dwarf_ctr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(pc, "pc", gcc_dwarf_pc, gcc_dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ { NULL, NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_cfa, gcc_dwarf_cfa, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, NULL, NULL},
+};
+
+static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
+
+const lldb_private::RegisterInfo *
+ABISysV_ppc64::GetRegisterInfoArray (uint32_t &count)
+{
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+
+size_t
+ABISysV_ppc64::GetRedZoneSize () const
+{
+ return 224;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABISysV_ppc64::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ if (arch.GetTriple().getArch() == llvm::Triple::ppc64)
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABISysV_ppc64);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABISysV_ppc64::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_ppc64::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
+
+ sp -= 8;
+
+ 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);
+ ProcessSP process_sp (thread.GetProcess());
+
+ RegisterValue reg_value;
+
+#if 0
+ // This code adds an extra frame so that we don't lose the function that we came from
+ // by pushing the PC and the FP and then writing the current FP to point to the FP value
+ // we just pushed. It is disabled for now until the stack backtracing code can be debugged.
+
+ // Save current PC
+ const RegisterInfo *fp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ if (reg_ctx->ReadRegister(pc_reg_info, reg_value))
+ {
+ if (log)
+ log->Printf("Pushing the current PC onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64());
+
+ if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error))
+ return false;
+
+ sp -= 8;
+
+ // Save current FP
+ if (reg_ctx->ReadRegister(fp_reg_info, reg_value))
+ {
+ if (log)
+ log->Printf("Pushing the current FP onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64());
+
+ if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error))
+ return false;
+ }
+ // Setup FP backchain
+ reg_value.SetUInt64 (sp);
+
+ if (log)
+ log->Printf("Writing FP: 0x%" PRIx64 " (for FP backchain)", reg_value.GetAsUInt64());
+
+ if (!reg_ctx->WriteRegister(fp_reg_info, reg_value))
+ {
+ return false;
+ }
+
+ sp -= 8;
+ }
+#endif
+
+ if (log)
+ log->Printf("Pushing the return address onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, (uint64_t)return_addr);
+
+ // Save return address onto the stack
+ if (!process_sp->WritePointerToMemory(sp, return_addr, error))
+ return false;
+
+ // %r1 is set to the actual stack value.
+
+ if (log)
+ log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_info, sp))
+ return false;
+
+ // %pc is set to the address of the called function.
+
+ if (log)
+ log->Printf("Writing IP: 0x%" PRIx64, (uint64_t)func_addr);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr))
+ return false;
+
+ return true;
+}
+
+static bool ReadIntegerArgument(Scalar &scalar,
+ unsigned int bit_width,
+ bool is_signed,
+ Thread &thread,
+ uint32_t *argument_register_ids,
+ unsigned int &current_argument_register,
+ addr_t &current_stack_argument)
+{
+ if (bit_width > 64)
+ return false; // Scalar can't hold large integer arguments
+
+ if (current_argument_register < 6)
+ {
+ scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned(argument_register_ids[current_argument_register], 0);
+ current_argument_register++;
+ if (is_signed)
+ scalar.SignExtend (bit_width);
+ }
+ else
+ {
+ uint32_t byte_size = (bit_width + (8-1))/8;
+ Error error;
+ if (thread.GetProcess()->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, is_signed, scalar, error))
+ {
+ current_stack_argument += byte_size;
+ return true;
+ }
+ return false;
+ }
+ return true;
+}
+
+bool
+ABISysV_ppc64::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ // Extract the register context so we can read arguments from registers
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ addr_t sp = reg_ctx->GetSP(0);
+
+ if (!sp)
+ return false;
+
+ addr_t current_stack_argument = sp + 48; // jump over return address
+
+ uint32_t argument_register_ids[8];
+
+ argument_register_ids[0] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1)->kinds[eRegisterKindLLDB];
+ argument_register_ids[1] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2)->kinds[eRegisterKindLLDB];
+ argument_register_ids[2] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG3)->kinds[eRegisterKindLLDB];
+ argument_register_ids[3] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG4)->kinds[eRegisterKindLLDB];
+ argument_register_ids[4] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG5)->kinds[eRegisterKindLLDB];
+ argument_register_ids[5] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG6)->kinds[eRegisterKindLLDB];
+ argument_register_ids[6] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG7)->kinds[eRegisterKindLLDB];
+ argument_register_ids[7] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG8)->kinds[eRegisterKindLLDB];
+
+ unsigned int current_argument_register = 0;
+
+ for (value_index = 0;
+ value_index < num_values;
+ ++value_index)
+ {
+ Value *value = values.GetValueAtIndex(value_index);
+
+ if (!value)
+ return false;
+
+ // We currently only support extracting values with Clang QualTypes.
+ // Do we care about others?
+ ClangASTType clang_type = value->GetClangType();
+ if (!clang_type)
+ return false;
+ bool is_signed;
+
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(),
+ is_signed,
+ thread,
+ argument_register_ids,
+ current_argument_register,
+ current_stack_argument);
+ }
+ else if (clang_type.IsPointerType ())
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(),
+ false,
+ thread,
+ argument_register_ids,
+ current_argument_register,
+ current_stack_argument);
+ }
+ }
+
+ return true;
+}
+
+Error
+ABISysV_ppc64::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())
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0);
+
+ 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)
+ {
+ uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (reg_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
+ {
+ size_t bit_width = clang_type.GetBitSize();
+ if (bit_width <= 64)
+ {
+ 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;
+ }
+
+ unsigned char buffer[16];
+ ByteOrder byte_order = data.GetByteOrder();
+
+ data.CopyByteOrderedData (0, num_bytes, buffer, 16, byte_order);
+ set_it_simple = true;
+ }
+ else
+ {
+ // FIXME - don't know how to do 80 bit long doubles yet.
+ error.SetErrorString ("We don't support returning float values > 64 bits at present");
+ }
+ }
+ }
+
+ if (!set_it_simple)
+ {
+ // Okay we've got a structure or something that doesn't fit in a simple register.
+ // We should figure out where it really goes, but we don't support this yet.
+ error.SetErrorString ("We only support setting simple integer and float return types at present.");
+ }
+
+ return error;
+}
+
+
+ValueObjectSP
+ABISysV_ppc64::GetReturnValueObjectSimple (Thread &thread,
+ ClangASTType &return_clang_type) const
+{
+ ValueObjectSP return_valobj_sp;
+ Value value;
+
+ if (!return_clang_type)
+ return return_valobj_sp;
+
+ //value.SetContext (Value::eContextTypeClangType, return_value_type);
+ 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 ();
+ 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
+
+ const size_t byte_size = return_clang_type.GetByteSize();
+ uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("r3", 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;
+ }
+ }
+ else if (type_flags & eTypeIsFloat)
+ {
+ if (type_flags & eTypeIsComplex)
+ {
+ // Don't handle complex yet.
+ }
+ else
+ {
+ const size_t byte_size = return_clang_type.GetByteSize();
+ if (byte_size <= sizeof(long double))
+ {
+ const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0);
+ RegisterValue f1_value;
+ if (reg_ctx->ReadRegister (f1_info, f1_value))
+ {
+ DataExtractor data;
+ if (f1_value.GetData(data))
+ {
+ lldb::offset_t offset = 0;
+ if (byte_size == sizeof(float))
+ {
+ value.GetScalar() = (float) data.GetFloat(&offset);
+ success = true;
+ }
+ else if (byte_size == sizeof(double))
+ {
+ value.GetScalar() = (double) data.GetDouble(&offset);
+ success = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success)
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+
+ }
+ else if (type_flags & eTypeIsPointer)
+ {
+ unsigned r3_id = reg_ctx->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB];
+ value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0);
+ value.SetValueType(Value::eValueTypeScalar);
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ }
+ else if (type_flags & eTypeIsVector)
+ {
+ const size_t byte_size = return_clang_type.GetByteSize();
+ if (byte_size > 0)
+ {
+
+ const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v0", 0);
+ if (altivec_reg == NULL)
+ altivec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0);
+ if (altivec_reg)
+ {
+ if (byte_size <= altivec_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(altivec_reg, reg_value))
+ {
+ Error error;
+ if (reg_value.GetAsMemoryData (altivec_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);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return return_valobj_sp;
+}
+
+ValueObjectSP
+ABISysV_ppc64::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;
+
+ const size_t bit_width = return_clang_type.GetBitSize();
+ if (return_clang_type.IsAggregateType())
+ {
+ Target *target = exe_ctx.GetTargetPtr();
+ bool is_memory = true;
+ if (bit_width <= 128)
+ {
+ ByteOrder target_byte_order = target->GetArchitecture().GetByteOrder();
+ DataBufferSP data_sp (new DataBufferHeap(16, 0));
+ DataExtractor return_ext (data_sp,
+ target_byte_order,
+ target->GetArchitecture().GetAddressByteSize());
+
+ const RegisterInfo *r3_info = reg_ctx_sp->GetRegisterInfoByName("r3", 0);
+ const RegisterInfo *rdx_info = reg_ctx_sp->GetRegisterInfoByName("rdx", 0);
+
+ RegisterValue r3_value, rdx_value;
+ reg_ctx_sp->ReadRegister (r3_info, r3_value);
+ reg_ctx_sp->ReadRegister (rdx_info, rdx_value);
+
+ DataExtractor r3_data, rdx_data;
+
+ r3_value.GetData(r3_data);
+ rdx_value.GetData(rdx_data);
+
+ uint32_t fp_bytes = 0; // Tracks how much of the xmm registers we've consumed so far
+ uint32_t integer_bytes = 0; // Tracks how much of the r3/rds registers we've consumed so far
+
+ const uint32_t num_children = return_clang_type.GetNumFields ();
+
+ // Since we are in the small struct regime, assume we are not in memory.
+ is_memory = false;
+
+ for (uint32_t idx = 0; idx < num_children; idx++)
+ {
+ std::string name;
+ uint64_t field_bit_offset = 0;
+ bool is_signed;
+ bool is_complex;
+ 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();
+
+ // If there are any unaligned fields, this is stored in memory.
+ if (field_bit_offset % field_bit_width != 0)
+ {
+ is_memory = true;
+ break;
+ }
+
+ uint32_t field_byte_width = field_bit_width/8;
+ uint32_t field_byte_offset = field_bit_offset/8;
+
+
+ DataExtractor *copy_from_extractor = NULL;
+ uint32_t copy_from_offset = 0;
+
+ if (field_clang_type.IsIntegerType (is_signed) || field_clang_type.IsPointerType ())
+ {
+ if (integer_bytes < 8)
+ {
+ if (integer_bytes + field_byte_width <= 8)
+ {
+ // This is in RAX, copy from register to our result structure:
+ copy_from_extractor = &r3_data;
+ copy_from_offset = integer_bytes;
+ integer_bytes += field_byte_width;
+ }
+ else
+ {
+ // The next field wouldn't fit in the remaining space, so we pushed it to rdx.
+ copy_from_extractor = &rdx_data;
+ copy_from_offset = 0;
+ integer_bytes = 8 + field_byte_width;
+
+ }
+ }
+ else if (integer_bytes + field_byte_width <= 16)
+ {
+ copy_from_extractor = &rdx_data;
+ copy_from_offset = integer_bytes - 8;
+ integer_bytes += field_byte_width;
+ }
+ else
+ {
+ // The last field didn't fit. I can't see how that would happen w/o the overall size being
+ // greater than 16 bytes. For now, return a NULL return value object.
+ return return_valobj_sp;
+ }
+ }
+ else if (field_clang_type.IsFloatingPointType (count, is_complex))
+ {
+ // Structs with long doubles are always passed in memory.
+ if (field_bit_width == 128)
+ {
+ is_memory = true;
+ break;
+ }
+ else if (field_bit_width == 64)
+ {
+ copy_from_offset = 0;
+ fp_bytes += field_byte_width;
+ }
+ else if (field_bit_width == 32)
+ {
+ // This one is kind of complicated. If we are in an "eightbyte" with another float, we'll
+ // be stuffed into an xmm register with it. If we are in an "eightbyte" with one or more ints,
+ // then we will be stuffed into the appropriate GPR with them.
+ bool in_gpr;
+ if (field_byte_offset % 8 == 0)
+ {
+ // We are at the beginning of one of the eightbytes, so check the next element (if any)
+ if (idx == num_children - 1)
+ in_gpr = false;
+ else
+ {
+ uint64_t next_field_bit_offset = 0;
+ ClangASTType next_field_clang_type = return_clang_type.GetFieldAtIndex (idx + 1,
+ name,
+ &next_field_bit_offset,
+ NULL,
+ NULL);
+ if (next_field_clang_type.IsIntegerType (is_signed))
+ in_gpr = true;
+ else
+ {
+ copy_from_offset = 0;
+ in_gpr = false;
+ }
+ }
+
+ }
+ else if (field_byte_offset % 4 == 0)
+ {
+ // We are inside of an eightbyte, so see if the field before us is floating point:
+ // This could happen if somebody put padding in the structure.
+ if (idx == 0)
+ in_gpr = false;
+ else
+ {
+ uint64_t prev_field_bit_offset = 0;
+ ClangASTType prev_field_clang_type = return_clang_type.GetFieldAtIndex (idx - 1,
+ name,
+ &prev_field_bit_offset,
+ NULL,
+ NULL);
+ if (prev_field_clang_type.IsIntegerType (is_signed))
+ in_gpr = true;
+ else
+ {
+ copy_from_offset = 4;
+ in_gpr = false;
+ }
+ }
+
+ }
+ else
+ {
+ is_memory = true;
+ continue;
+ }
+
+ // Okay, we've figured out whether we are in GPR or XMM, now figure out which one.
+ if (in_gpr)
+ {
+ if (integer_bytes < 8)
+ {
+ // This is in RAX, copy from register to our result structure:
+ copy_from_extractor = &r3_data;
+ copy_from_offset = integer_bytes;
+ integer_bytes += field_byte_width;
+ }
+ else
+ {
+ copy_from_extractor = &rdx_data;
+ copy_from_offset = integer_bytes - 8;
+ integer_bytes += field_byte_width;
+ }
+ }
+ else
+ {
+ fp_bytes += field_byte_width;
+ }
+ }
+ }
+
+ // These two tests are just sanity checks. If I somehow get the
+ // type calculation wrong above it is better to just return nothing
+ // than to assert or crash.
+ if (!copy_from_extractor)
+ return return_valobj_sp;
+ if (copy_from_offset + field_byte_width > copy_from_extractor->GetByteSize())
+ return return_valobj_sp;
+
+ copy_from_extractor->CopyByteOrderedData (copy_from_offset,
+ field_byte_width,
+ data_sp->GetBytes() + field_byte_offset,
+ field_byte_width,
+ target_byte_order);
+ }
+
+ if (!is_memory)
+ {
+ // The result is in our data buffer. Let's make a variable object out of it:
+ return_valobj_sp = ValueObjectConstResult::Create (&thread,
+ return_clang_type,
+ ConstString(""),
+ return_ext);
+ }
+ }
+
+
+ // FIXME: This is just taking a guess, r3 may very well no longer hold the return storage location.
+ // If we are going to do this right, when we make a new frame we should check to see if it uses a memory
+ // return, and if we are at the first instruction and if so stash away the return location. Then we would
+ // only return the memory return value if we know it is valid.
+
+ if (is_memory)
+ {
+ unsigned r3_id = reg_ctx_sp->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB];
+ lldb::addr_t storage_addr = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0);
+ return_valobj_sp = ValueObjectMemory::Create (&thread,
+ "",
+ Address (storage_addr, NULL),
+ return_clang_type);
+ }
+ }
+
+ return return_valobj_sp;
+}
+
+bool
+ABISysV_ppc64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ uint32_t lr_reg_num = gcc_dwarf_lr;
+ uint32_t sp_reg_num = gcc_dwarf_r1;
+ uint32_t pc_reg_num = gcc_dwarf_pc;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ // Our Call Frame Address is the stack pointer value
+ row->SetCFARegister (sp_reg_num);
+
+ // 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 ("ppc64 at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+
+ return true;
+}
+
+bool
+ABISysV_ppc64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ uint32_t sp_reg_num = gcc_dwarf_r1;
+ uint32_t pc_reg_num = gcc_dwarf_lr;
+
+ 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->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 2, true);
+ row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(gcc_dwarf_cr, ptr_size, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("ppc64 default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ unwind_plan.SetReturnAddressRegister(gcc_dwarf_lr);
+ return true;
+}
+
+bool
+ABISysV_ppc64::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ return !RegisterIsCalleeSaved (reg_info);
+}
+
+
+
+// See "Register Usage" in the
+// "System V Application Binary Interface"
+// "64-bit PowerPC ELF Application Binary Interface Supplement"
+// current version is 1.9 released 2004 at http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.pdf
+
+bool
+ABISysV_ppc64::RegisterIsCalleeSaved (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ // Preserved registers are :
+ // r1,r2,r13-r31
+ // cr2-cr4 (partially preserved)
+ // f14-f31 (not yet)
+ // v20-v31 (not yet)
+ // vrsave (not yet)
+
+ const char *name = reg_info->name;
+ if (name[0] == 'r')
+ {
+ if ((name[1] == '1' || name[1] == '2') && name[2] == '\0')
+ return true;
+ if (name[1] == '1' && name[2] > '2')
+ return true;
+ if ((name[1] == '2' || name[1] == '3') && name[2] != '\0')
+ return true;
+ }
+
+ if (name[0] == 'f' && name[1] >= '0' && name[2] <= '9')
+ {
+ if (name[2] == '\0')
+ return false;
+ if (name[1] == '1' && name[2] >= '4')
+ return true;
+ if ((name[1] == '2' || name[1] == '3') && name[2] != '\0')
+ return true;
+ }
+
+ 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_ppc64::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "System V ABI for ppc64 targets",
+ CreateInstance);
+}
+
+void
+ABISysV_ppc64::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABISysV_ppc64::GetPluginNameStatic()
+{
+ static ConstString g_name("sysv-ppc64");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABISysV_ppc64::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABISysV_ppc64::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h
new file mode 100644
index 000000000000..d77cb9f1efe3
--- /dev/null
+++ b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h
@@ -0,0 +1,143 @@
+//===-- ABISysV_ppc64.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_ppc64_h_
+#define liblldb_ABISysV_ppc64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABISysV_ppc64 :
+ public lldb_private::ABI
+{
+public:
+
+ ~ABISysV_ppc64()
+ {
+ }
+
+ 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
+ StackUsesFrames ()
+ {
+ return true;
+ }
+
+ // The SysV ppc64 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)
+ {
+ // We have a 64 bit address space, so anything is valid as opcodes
+ // aren't fixed width...
+ return true;
+ }
+
+ virtual bool
+ FunctionCallsChangeCFA ()
+ {
+ 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_ppc64() : lldb_private::ABI() { } // Call CreateInstance instead.
+};
+
+#endif // liblldb_ABI_h_
diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
index b537415bf055..776e7fea67c7 100644
--- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -649,18 +649,18 @@ ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread,
return return_valobj_sp;
const uint32_t type_flags = return_clang_type.GetTypeInfo ();
- if (type_flags & ClangASTType::eTypeIsScalar)
+ if (type_flags & eTypeIsScalar)
{
value.SetValueType(Value::eValueTypeScalar);
bool success = false;
- if (type_flags & ClangASTType::eTypeIsInteger)
+ if (type_flags & eTypeIsInteger)
{
// Extract the register context so we can read arguments from registers
const size_t byte_size = return_clang_type.GetByteSize();
uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("rax", 0), 0);
- const bool is_signed = (type_flags & ClangASTType::eTypeIsSigned) != 0;
+ const bool is_signed = (type_flags & eTypeIsSigned) != 0;
switch (byte_size)
{
default:
@@ -699,9 +699,9 @@ ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread,
break;
}
}
- else if (type_flags & ClangASTType::eTypeIsFloat)
+ else if (type_flags & eTypeIsFloat)
{
- if (type_flags & ClangASTType::eTypeIsComplex)
+ if (type_flags & eTypeIsComplex)
{
// Don't handle complex yet.
}
@@ -744,7 +744,7 @@ ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread,
ConstString(""));
}
- else if (type_flags & ClangASTType::eTypeIsPointer)
+ else if (type_flags & eTypeIsPointer)
{
unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0);
@@ -753,7 +753,7 @@ ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread,
value,
ConstString(""));
}
- else if (type_flags & ClangASTType::eTypeIsVector)
+ else if (type_flags & eTypeIsVector)
{
const size_t byte_size = return_clang_type.GetByteSize();
if (byte_size > 0)
diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
index 7fd1b6c4b0f3..6fefcc2a9c74 100644
--- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
@@ -61,13 +61,7 @@ public:
virtual bool
RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info);
-
- virtual bool
- StackUsesFrames ()
- {
- return true;
- }
-
+
// The SysV x86_64 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
@@ -97,12 +91,6 @@ public:
return true;
}
- virtual bool
- FunctionCallsChangeCFA ()
- {
- return true;
- }
-
virtual const lldb_private::RegisterInfo *
GetRegisterInfoArray (uint32_t &count);
//------------------------------------------------------------------
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
index c14371d0589c..97ddbef0e307 100644
--- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
+++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
@@ -21,7 +21,6 @@
#include "llvm/MC/MCRelocationInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MemoryObject.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/ADT/SmallString.h"
@@ -489,41 +488,19 @@ DisassemblerLLVMC::LLVMCDisassembler::~LLVMCDisassembler()
{
}
-namespace {
- // This is the memory object we use in GetInstruction.
- class LLDBDisasmMemoryObject : public llvm::MemoryObject {
- const uint8_t *m_bytes;
- uint64_t m_size;
- uint64_t m_base_PC;
- public:
- LLDBDisasmMemoryObject(const uint8_t *bytes, uint64_t size, uint64_t basePC) :
- m_bytes(bytes), m_size(size), m_base_PC(basePC) {}
-
- uint64_t getBase() const { return m_base_PC; }
- uint64_t getExtent() const { return m_size; }
-
- int readByte(uint64_t addr, uint8_t *byte) const {
- if (addr - m_base_PC >= m_size)
- return -1;
- *byte = m_bytes[addr - m_base_PC];
- return 0;
- }
- };
-} // End Anonymous Namespace
-
uint64_t
DisassemblerLLVMC::LLVMCDisassembler::GetMCInst (const uint8_t *opcode_data,
size_t opcode_data_len,
lldb::addr_t pc,
llvm::MCInst &mc_inst)
{
- LLDBDisasmMemoryObject memory_object (opcode_data, opcode_data_len, pc);
+ llvm::ArrayRef<uint8_t> data(opcode_data, opcode_data_len);
llvm::MCDisassembler::DecodeStatus status;
uint64_t new_inst_size;
status = m_disasm_ap->getInstruction(mc_inst,
new_inst_size,
- memory_object,
+ data,
pc,
llvm::nulls(),
llvm::nulls());
@@ -832,11 +809,19 @@ const char *DisassemblerLLVMC::SymbolLookup (uint64_t value,
value_so_addr.Dump (&ss,
target,
- Address::DumpStyleResolvedDescriptionNoModule,
+ Address::DumpStyleResolvedDescriptionNoFunctionArguments,
Address::DumpStyleSectionNameOffset);
if (!ss.GetString().empty())
{
+ // If Address::Dump returned a multi-line description, most commonly seen when we
+ // have multiple levels of inlined functions at an address, only show the first line.
+ std::string &str(ss.GetString());
+ size_t first_eol_char = str.find_first_of ("\r\n");
+ if (first_eol_char != std::string::npos)
+ {
+ str.erase (first_eol_char);
+ }
m_inst->AppendComment(ss.GetString());
}
}
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
index 0e203fe43a79..d8279e44e14a 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
@@ -34,6 +34,13 @@ ResolveRendezvousAddress(Process *process)
addr_t info_addr;
Error error;
+ if (!process)
+ {
+ if (log)
+ log->Printf ("%s null process provided", __FUNCTION__);
+ return LLDB_INVALID_ADDRESS;
+ }
+
// Try to get it from our process. This might be a remote process and might
// grab it via some remote-specific mechanism.
info_location = process->GetImageInfoAddress();
@@ -43,7 +50,7 @@ ResolveRendezvousAddress(Process *process)
// If the process fails to return an address, fall back to seeing if the local object file can help us find it.
if (info_location == LLDB_INVALID_ADDRESS)
{
- Target *target = process ? &process->GetTarget() : nullptr;
+ Target *target = &process->GetTarget();
if (target)
{
ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
@@ -70,6 +77,9 @@ ResolveRendezvousAddress(Process *process)
return LLDB_INVALID_ADDRESS;
}
+ if (log)
+ log->Printf ("%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64, __FUNCTION__, process->GetAddressByteSize(), info_location);
+
info_addr = process->ReadPointerFromMemory(info_location, error);
if (error.Fail())
{
@@ -193,7 +203,7 @@ 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);
+ assert(m_previous.state == eConsistent || (m_previous.state == eAdd && m_current.state == eDelete));
m_soentries.clear();
m_added_soentries.clear();
m_removed_soentries.clear();
@@ -320,23 +330,11 @@ DYLDRendezvous::ReadStringFromMemory(addr_t addr)
{
std::string str;
Error error;
- size_t size;
- char c;
if (addr == LLDB_INVALID_ADDRESS)
return std::string();
- for (;;) {
- size = m_process->DoReadMemory(addr, &c, 1, error);
- if (size != 1 || error.Fail())
- return std::string();
- if (c == 0)
- break;
- else {
- str.push_back(c);
- addr++;
- }
- }
+ m_process->ReadCStringFromMemory(addr, str, error);
return str;
}
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index 549e5f9b5345..6b0b6f5cc8b8 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -111,27 +111,88 @@ DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD()
void
DynamicLoaderPOSIXDYLD::DidAttach()
{
- ModuleSP executable;
- addr_t load_offset;
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID);
m_auxv.reset(new AuxVector(m_process));
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reloaded auxv data", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID);
- executable = GetTargetExecutable();
- load_offset = ComputeLoadOffset();
+ 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);
+ }
+ }
- if (executable.get() && load_offset != LLDB_INVALID_ADDRESS)
+ 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 (executable_sp && load_offset != LLDB_INVALID_ADDRESS)
{
ModuleList module_list;
- module_list.Append(executable);
- UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset);
- LoadAllCurrentModules();
+
+ module_list.Append(executable_sp);
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " added executable '%s' to module load list",
+ __FUNCTION__,
+ m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID,
+ executable_sp->GetFileSpec().GetPath().c_str ());
+
+ UpdateLoadedSections(executable_sp, LLDB_INVALID_ADDRESS, load_offset);
+
+ // When attaching to a target, there are two possible states:
+ // (1) We already crossed the entry point and therefore the rendezvous
+ // structure is ready to be used and we can load the list of modules
+ // and place the rendezvous breakpoint.
+ // (2) We didn't cross the entry point yet, so these structures are not
+ // ready; we should behave as if we just launched the target and
+ // call ProbeEntry(). This will place a breakpoint on the entry
+ // point which itself will be hit after the rendezvous structure is
+ // set up and will perform actions described in (1).
+ if (m_rendezvous.Resolve())
+ {
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64 " rendezvous could resolve: attach assuming dynamic loader info is available now", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID);
+ LoadAllCurrentModules();
+ SetRendezvousBreakpoint();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64 " rendezvous could not yet resolve: adding breakpoint to catch future rendezvous setup", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID);
+ ProbeEntry();
+ }
+
m_process->GetTarget().ModulesDidLoad(module_list);
+ if (log)
+ {
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s told the target about the modules that loaded:", __FUNCTION__);
+ for (auto module_sp : module_list.Modules ())
+ {
+ log->Printf ("-- [module] %s (pid %" PRIu64 ")",
+ module_sp ? module_sp->GetFileSpec().GetPath().c_str () : "<null>",
+ m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID);
+ }
+ }
}
}
void
DynamicLoaderPOSIXDYLD::DidLaunch()
{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s()", __FUNCTION__);
+
ModuleSP executable;
addr_t load_offset;
@@ -145,7 +206,11 @@ DynamicLoaderPOSIXDYLD::DidLaunch()
ModuleList module_list;
module_list.Append(executable);
UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset);
+
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s about to call ProbeEntry()", __FUNCTION__);
ProbeEntry();
+
m_process->GetTarget().ModulesDidLoad(module_list);
}
}
@@ -187,15 +252,28 @@ DynamicLoaderPOSIXDYLD::UnloadSections(const ModuleSP module)
void
DynamicLoaderPOSIXDYLD::ProbeEntry()
{
- Breakpoint *entry_break;
- addr_t entry;
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
- if ((entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
+ const addr_t entry = GetEntryPoint();
+ if (entry == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " GetEntryPoint() returned no address, not setting entry breakpoint", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID);
return;
-
- entry_break = m_process->GetTarget().CreateBreakpoint(entry, true, false).get();
- entry_break->SetCallback(EntryBreakpointHit, this, true);
- entry_break->SetBreakpointKind("shared-library-event");
+ }
+
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " GetEntryPoint() returned address 0x%" PRIx64 ", setting entry breakpoint", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, entry);
+
+ if (m_process)
+ {
+ Breakpoint *const entry_break = m_process->GetTarget().CreateBreakpoint(entry, true, false).get();
+ entry_break->SetCallback(EntryBreakpointHit, this, true);
+ entry_break->SetBreakpointKind("shared-library-event");
+
+ // Shoudn't hit this more than once.
+ entry_break->SetOneShot (true);
+ }
}
// The runtime linker has run and initialized the rendezvous structure once the
@@ -210,9 +288,40 @@ DynamicLoaderPOSIXDYLD::EntryBreakpointHit(void *baton,
user_id_t break_id,
user_id_t break_loc_id)
{
- DynamicLoaderPOSIXDYLD* dyld_instance;
+ assert(baton && "null baton");
+ if (!baton)
+ return false;
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ DynamicLoaderPOSIXDYLD *const dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton);
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64, __FUNCTION__, dyld_instance->m_process ? dyld_instance->m_process->GetID () : LLDB_INVALID_PROCESS_ID);
+
+ // Disable the breakpoint --- if a stop happens right after this, which we've seen on occasion, we don't
+ // want the breakpoint stepping thread-plan logic to show a breakpoint instruction at the disassembled
+ // entry point to the program. Disabling it prevents it. (One-shot is not enough - one-shot removal logic
+ // only happens after the breakpoint goes public, which wasn't happening in our scenario).
+ if (dyld_instance->m_process)
+ {
+ BreakpointSP breakpoint_sp = dyld_instance->m_process->GetTarget().GetBreakpointByID (break_id);
+ if (breakpoint_sp)
+ {
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " disabling breakpoint id %" PRIu64, __FUNCTION__, dyld_instance->m_process->GetID (), break_id);
+ breakpoint_sp->SetEnabled (false);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " failed to find breakpoint for breakpoint id %" PRIu64, __FUNCTION__, dyld_instance->m_process->GetID (), break_id);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s breakpoint id %" PRIu64 " no Process instance! Cannot disable breakpoint", __FUNCTION__, break_id);
+ }
- dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton);
dyld_instance->LoadAllCurrentModules();
dyld_instance->SetRendezvousBreakpoint();
return false; // Continue running.
@@ -221,16 +330,25 @@ DynamicLoaderPOSIXDYLD::EntryBreakpointHit(void *baton,
void
DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint()
{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
addr_t break_addr = m_rendezvous.GetBreakAddress();
Target &target = m_process->GetTarget();
if (m_dyld_bid == LLDB_INVALID_BREAK_ID)
{
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " setting rendezvous break address at 0x%" PRIx64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, break_addr);
Breakpoint *dyld_break = target.CreateBreakpoint (break_addr, true, false).get();
dyld_break->SetCallback(RendezvousBreakpointHit, this, true);
dyld_break->SetBreakpointKind ("shared-library-event");
m_dyld_bid = dyld_break->GetID();
}
+ else
+ {
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reusing break id %" PRIu32 ", address at 0x%" PRIx64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, m_dyld_bid, break_addr);
+ }
// Make sure our breakpoint is at the right address.
assert (target.GetBreakpointByID(m_dyld_bid)->FindLocationByAddress(break_addr)->GetBreakpoint().GetID() == m_dyld_bid);
@@ -242,13 +360,22 @@ DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit(void *baton,
user_id_t break_id,
user_id_t break_loc_id)
{
- DynamicLoaderPOSIXDYLD* dyld_instance;
+ assert (baton && "null baton");
+ if (!baton)
+ return false;
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ DynamicLoaderPOSIXDYLD *const dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton);
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64, __FUNCTION__, dyld_instance->m_process ? dyld_instance->m_process->GetID () : LLDB_INVALID_PROCESS_ID);
- dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton);
dyld_instance->RefreshModules();
// Return true to stop the target, false to just let the target run.
- return dyld_instance->GetStopWhenImagesChange();
+ const bool stop_when_images_change = dyld_instance->GetStopWhenImagesChange();
+ if (log)
+ log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " stop_when_images_change=%s", __FUNCTION__, dyld_instance->m_process ? dyld_instance->m_process->GetID () : LLDB_INVALID_PROCESS_ID, stop_when_images_change ? "true" : "false");
+ return stop_when_images_change;
}
void
@@ -439,6 +566,13 @@ DynamicLoaderPOSIXDYLD::GetEntryPoint()
return LLDB_INVALID_ADDRESS;
m_entry_point = static_cast<addr_t>(I->value);
+
+ const ArchSpec &arch = m_process->GetTarget().GetArchitecture();
+
+ // On ppc64, the entry point is actually a descriptor. Dereference it.
+ if (arch.GetMachine() == llvm::Triple::ppc64)
+ m_entry_point = ReadUnsignedIntWithSizeInBytes(m_entry_point, 8);
+
return m_entry_point;
}
@@ -487,3 +621,18 @@ DynamicLoaderPOSIXDYLD::GetThreadLocalData (const lldb::ModuleSP module, const l
return tls_block;
}
+
+bool
+DynamicLoaderPOSIXDYLD::GetProcessModuleSpec (ModuleSpec& module_spec)
+{
+ if (m_process == nullptr)
+ return false;
+
+ auto& target = m_process->GetTarget ();
+ ProcessInstanceInfo process_info;
+ if (!target.GetPlatform ()->GetProcessInfo (m_process->GetID (), process_info))
+ return false;
+
+ module_spec = ModuleSpec (process_info.GetExecutableFile (), process_info.GetArchitecture ());
+ return true;
+}
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
index 9ced5da8a015..747ff3f2be36 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
@@ -168,6 +168,10 @@ protected:
lldb::addr_t
GetEntryPoint();
+ /// Loads ModuleSpec data from inferior process.
+ bool
+ GetProcessModuleSpec(lldb_private::ModuleSpec& module_spec);
+
private:
DISALLOW_COPY_AND_ASSIGN(DynamicLoaderPOSIXDYLD);
};
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
index fa8681ed69fe..bc358a985248 100644
--- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
@@ -9873,12 +9873,14 @@ EmulateInstructionARM::EmulateSTREX (const uint32_t opcode, const ARMEncoding en
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 0))
return false;
}
+#if 0 // unreachable because if true
else
{
// R[d] = 1;
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 1))
return false;
}
+#endif // unreachable because if true
}
return true;
}
diff --git a/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp b/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp
new file mode 100644
index 000000000000..96754ff78787
--- /dev/null
+++ b/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp
@@ -0,0 +1,314 @@
+//===-- AddressSanitizerRuntime.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AddressSanitizerRuntime.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+lldb::InstrumentationRuntimeSP
+AddressSanitizerRuntime::CreateInstance (const lldb::ProcessSP &process_sp)
+{
+ return InstrumentationRuntimeSP(new AddressSanitizerRuntime(process_sp));
+}
+
+void
+AddressSanitizerRuntime::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "AddressSanitizer instrumentation runtime plugin.",
+ CreateInstance,
+ GetTypeStatic);
+}
+
+void
+AddressSanitizerRuntime::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+AddressSanitizerRuntime::GetPluginNameStatic()
+{
+ return ConstString("AddressSanitizer");
+}
+
+lldb::InstrumentationRuntimeType
+AddressSanitizerRuntime::GetTypeStatic()
+{
+ return eInstrumentationRuntimeTypeAddressSanitizer;
+}
+
+AddressSanitizerRuntime::AddressSanitizerRuntime(const ProcessSP &process_sp) :
+ m_is_active(false),
+ m_runtime_module(),
+ m_process(process_sp),
+ m_breakpoint_id(0)
+{
+}
+
+AddressSanitizerRuntime::~AddressSanitizerRuntime()
+{
+ Deactivate();
+}
+
+bool ModuleContainsASanRuntime(Module * module)
+{
+ SymbolContextList sc_list;
+ const bool include_symbols = true;
+ const bool append = true;
+ const bool include_inlines = true;
+
+ size_t num_matches = module->FindFunctions(ConstString("__asan_get_alloc_stack"), NULL, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
+
+ return num_matches > 0;
+}
+
+void
+AddressSanitizerRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list)
+{
+ if (IsActive())
+ return;
+
+ if (m_runtime_module) {
+ Activate();
+ return;
+ }
+
+ Mutex::Locker modules_locker(module_list.GetMutex());
+ const size_t num_modules = module_list.GetSize();
+ for (size_t i = 0; i < num_modules; ++i)
+ {
+ Module *module_pointer = module_list.GetModulePointerAtIndexUnlocked(i);
+ const FileSpec & file_spec = module_pointer->GetFileSpec();
+ if (! file_spec)
+ continue;
+
+ static RegularExpression g_asan_runtime_regex("libclang_rt.asan_(.*)_dynamic\\.dylib");
+ if (g_asan_runtime_regex.Execute (file_spec.GetFilename().GetCString()) || module_pointer->IsExecutable())
+ {
+ if (ModuleContainsASanRuntime(module_pointer))
+ {
+ m_runtime_module = module_pointer->shared_from_this();
+ Activate();
+ return;
+ }
+ }
+ }
+}
+
+bool
+AddressSanitizerRuntime::IsActive()
+{
+ return m_is_active;
+}
+
+#define RETRIEVE_REPORT_DATA_FUNCTION_TIMEOUT_USEC 2*1000*1000
+
+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;
+
+ 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;
+)";
+
+StructuredData::ObjectSP
+AddressSanitizerRuntime::RetrieveReportData()
+{
+ ThreadSP thread_sp = m_process->GetThreadList().GetSelectedThread();
+ StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
+
+ if (!frame_sp)
+ return StructuredData::ObjectSP();
+
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError(true);
+ options.SetTryAllThreads(true);
+ options.SetStopOthers(true);
+ options.SetIgnoreBreakpoints(true);
+ options.SetTimeoutUsec(RETRIEVE_REPORT_DATA_FUNCTION_TIMEOUT_USEC);
+
+ ValueObjectSP return_value_sp;
+ if (m_process->GetTarget().EvaluateExpression(address_sanitizer_retrieve_report_data_command, frame_sp.get(), return_value_sp, options) != eExpressionCompleted)
+ return StructuredData::ObjectSP();
+
+ int present = return_value_sp->GetValueForExpressionPath(".present")->GetValueAsUnsigned(0);
+ if (present != 1)
+ return StructuredData::ObjectSP();
+
+ addr_t pc = return_value_sp->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0);
+ 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);
+ addr_t description_ptr = return_value_sp->GetValueForExpressionPath(".description")->GetValueAsUnsigned(0);
+ std::string description;
+ Error error;
+ m_process->ReadCStringFromMemory(description_ptr, description, error);
+
+ StructuredData::Dictionary *dict = new StructuredData::Dictionary();
+ dict->AddStringItem("instrumentation_class", "AddressSanitizer");
+ dict->AddStringItem("stop_type", "fatal_error");
+ dict->AddIntegerItem("pc", pc);
+ dict->AddIntegerItem("bp", bp);
+ dict->AddIntegerItem("sp", sp);
+ dict->AddIntegerItem("address", address);
+ dict->AddIntegerItem("access_type", access_type);
+ dict->AddIntegerItem("access_size", access_size);
+ dict->AddStringItem("description", description);
+
+ return StructuredData::ObjectSP(dict);
+}
+
+std::string
+AddressSanitizerRuntime::FormatDescription(StructuredData::ObjectSP report)
+{
+ std::string description = report->GetAsDictionary()->GetValueForKey("description")->GetAsString()->GetValue();
+ if (description == "heap-use-after-free") {
+ return "Use of deallocated memory detected";
+ } else if (description == "heap-buffer-overflow") {
+ return "Heap buffer overflow detected";
+ } else if (description == "stack-buffer-underflow") {
+ return "Stack buffer underflow detected";
+ } else if (description == "initialization-order-fiasco") {
+ return "Initialization order problem detected";
+ } else if (description == "stack-buffer-overflow") {
+ return "Stack buffer overflow detected";
+ } else if (description == "stack-use-after-return") {
+ return "Use of returned stack memory detected";
+ } else if (description == "use-after-poison") {
+ return "Use of poisoned memory detected";
+ } else if (description == "container-overflow") {
+ return "Container overflow detected";
+ } else if (description == "stack-use-after-scope") {
+ return "Use of out-of-scope stack memory detected";
+ } else if (description == "global-buffer-overflow") {
+ return "Global buffer overflow detected";
+ } else if (description == "unknown-crash") {
+ return "Invalid memory access detected";
+ }
+
+ // for unknown report codes just show the code
+ return description;
+}
+
+bool
+AddressSanitizerRuntime::NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, user_id_t break_id, user_id_t break_loc_id)
+{
+ assert (baton && "null baton");
+ if (!baton)
+ return false;
+
+ AddressSanitizerRuntime *const instance = static_cast<AddressSanitizerRuntime*>(baton);
+
+ StructuredData::ObjectSP report = instance->RetrieveReportData();
+ std::string description;
+ if (report) {
+ description = instance->FormatDescription(report);
+ }
+ ThreadSP thread = context->exe_ctx_ref.GetThreadSP();
+ thread->SetStopInfo(InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(*thread, description.c_str(), report));
+
+ if (instance->m_process)
+ {
+ StreamFileSP stream_sp (instance->m_process->GetTarget().GetDebugger().GetOutputFile());
+ if (stream_sp)
+ {
+ stream_sp->Printf ("AddressSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.\n");
+ }
+ }
+ // Return true to stop the target, false to just let the target run.
+ return true;
+}
+
+void
+AddressSanitizerRuntime::Activate()
+{
+ if (m_is_active)
+ return;
+
+ ConstString symbol_name ("__asan::AsanDie()");
+ const Symbol *symbol = m_runtime_module->FindFirstSymbolWithNameAndType (symbol_name, eSymbolTypeCode);
+
+ if (symbol == NULL)
+ return;
+
+ if (!symbol->GetAddress().IsValid())
+ return;
+
+ Target &target = m_process->GetTarget();
+ addr_t symbol_address = symbol->GetAddress().GetOpcodeLoadAddress(&target);
+
+ if (symbol_address == LLDB_INVALID_ADDRESS)
+ return;
+
+ bool internal = true;
+ bool hardware = false;
+ Breakpoint *breakpoint = m_process->GetTarget().CreateBreakpoint(symbol_address, internal, hardware).get();
+ breakpoint->SetCallback (AddressSanitizerRuntime::NotifyBreakpointHit, this, true);
+ breakpoint->SetBreakpointKind ("address-sanitizer-report");
+ m_breakpoint_id = breakpoint->GetID();
+
+ if (m_process)
+ {
+ StreamFileSP stream_sp (m_process->GetTarget().GetDebugger().GetOutputFile());
+ if (stream_sp)
+ {
+ stream_sp->Printf ("AddressSanitizer debugger support is active. Memory error breakpoint has been installed and you can now use the 'memory history' command.\n");
+ }
+ }
+
+ m_is_active = true;
+}
+
+void
+AddressSanitizerRuntime::Deactivate()
+{
+ if (m_breakpoint_id != LLDB_INVALID_BREAK_ID)
+ {
+ m_process->GetTarget().RemoveBreakpointByID(m_breakpoint_id);
+ m_breakpoint_id = LLDB_INVALID_BREAK_ID;
+ }
+ m_is_active = false;
+}
diff --git a/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h b/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h
new file mode 100644
index 000000000000..69c134cbedaf
--- /dev/null
+++ b/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h
@@ -0,0 +1,86 @@
+//===-- AddressSanitizerRuntime.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_AddressSanitizerRuntime_h_
+#define liblldb_AddressSanitizerRuntime_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/InstrumentationRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/StructuredData.h"
+
+namespace lldb_private {
+
+class AddressSanitizerRuntime : public lldb_private::InstrumentationRuntime
+{
+public:
+
+ static lldb::InstrumentationRuntimeSP
+ CreateInstance (const lldb::ProcessSP &process_sp);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static lldb::InstrumentationRuntimeType
+ GetTypeStatic();
+
+ virtual
+ ~AddressSanitizerRuntime();
+
+ virtual lldb_private::ConstString
+ GetPluginName() { return GetPluginNameStatic(); }
+
+ virtual lldb::InstrumentationRuntimeType
+ GetType() { return GetTypeStatic(); }
+
+ virtual uint32_t
+ GetPluginVersion() { return 1; }
+
+ virtual void
+ ModulesDidLoad(lldb_private::ModuleList &module_list);
+
+ virtual bool
+ IsActive();
+
+private:
+
+ AddressSanitizerRuntime(const lldb::ProcessSP &process_sp);
+
+ void
+ Activate();
+
+ void
+ Deactivate();
+
+ static bool
+ NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+
+ StructuredData::ObjectSP
+ RetrieveReportData();
+
+ std::string
+ FormatDescription(StructuredData::ObjectSP report);
+
+ bool m_is_active;
+ lldb::ModuleSP m_runtime_module;
+ lldb::ProcessSP m_process;
+ lldb::user_id_t m_breakpoint_id;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_InstrumentationRuntime_h_
diff --git a/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
index 905984d33410..cd303cb0768f 100644
--- a/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
+++ b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
@@ -36,21 +36,24 @@ typedef enum
JIT_UNREGISTER_FN
} jit_actions_t;
+#pragma pack(push, 4)
+template <typename ptr_t>
struct jit_code_entry
{
- struct jit_code_entry *next_entry;
- struct jit_code_entry *prev_entry;
- const char *symfile_addr;
+ ptr_t next_entry; // pointer
+ ptr_t prev_entry; // pointer
+ ptr_t symfile_addr; // pointer
uint64_t symfile_size;
};
-
+template <typename ptr_t>
struct jit_descriptor
{
uint32_t version;
uint32_t action_flag; // Values are jit_action_t
- struct jit_code_entry *relevant_entry;
- struct jit_code_entry *first_entry;
+ ptr_t relevant_entry; // pointer
+ ptr_t first_entry; // pointer
};
+#pragma pack(pop)
JITLoaderGDB::JITLoaderGDB (lldb_private::Process *process) :
JITLoader(process),
@@ -198,6 +201,17 @@ static void updateSectionLoadAddress(const SectionList &section_list,
bool
JITLoaderGDB::ReadJITDescriptor(bool all_entries)
{
+ Target &target = m_process->GetTarget();
+ if (target.GetArchitecture().GetAddressByteSize() == 8)
+ return ReadJITDescriptorImpl<uint64_t>(all_entries);
+ else
+ return ReadJITDescriptorImpl<uint32_t>(all_entries);
+}
+
+template <typename ptr_t>
+bool
+JITLoaderGDB::ReadJITDescriptorImpl(bool all_entries)
+{
if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS)
return false;
@@ -205,7 +219,7 @@ JITLoaderGDB::ReadJITDescriptor(bool all_entries)
Target &target = m_process->GetTarget();
ModuleList &module_list = target.GetImages();
- jit_descriptor jit_desc;
+ jit_descriptor<ptr_t> jit_desc;
const size_t jit_desc_size = sizeof(jit_desc);
Error error;
size_t bytes_read = m_process->DoReadMemory(
@@ -228,7 +242,7 @@ JITLoaderGDB::ReadJITDescriptor(bool all_entries)
while (jit_relevant_entry != 0)
{
- jit_code_entry jit_entry;
+ jit_code_entry<ptr_t> jit_entry;
const size_t jit_entry_size = sizeof(jit_entry);
bytes_read = m_process->DoReadMemory(jit_relevant_entry, &jit_entry, jit_entry_size, error);
if (bytes_read != jit_entry_size || !error.Success())
diff --git a/source/Plugins/JITLoader/GDB/JITLoaderGDB.h b/source/Plugins/JITLoader/GDB/JITLoaderGDB.h
index 5fa66b874972..bfa1721d3349 100644
--- a/source/Plugins/JITLoader/GDB/JITLoaderGDB.h
+++ b/source/Plugins/JITLoader/GDB/JITLoaderGDB.h
@@ -81,6 +81,10 @@ private:
bool
ReadJITDescriptor(bool all_entries);
+ template <typename ptr_t>
+ bool
+ ReadJITDescriptorImpl(bool all_entries);
+
static bool
JITDebugBreakpointHit(void *baton,
lldb_private::StoppointCallbackContext *context,
diff --git a/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
new file mode 100644
index 000000000000..c7c64ed54d87
--- /dev/null
+++ b/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
@@ -0,0 +1,183 @@
+//===-- MemoryHistoryASan.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MemoryHistoryASan.h"
+
+#include "lldb/Target/MemoryHistory.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/ThreadList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Core/Module.h"
+#include "Plugins/Process/Utility/HistoryThread.h"
+#include "lldb/Core/ValueObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+MemoryHistorySP
+MemoryHistoryASan::CreateInstance (const ProcessSP &process_sp)
+{
+ if (!process_sp.get())
+ return NULL;
+
+ Target & target = process_sp->GetTarget();
+
+ bool found_asan_runtime = false;
+
+ const ModuleList &target_modules = target.GetImages();
+ Mutex::Locker modules_locker(target_modules.GetMutex());
+ const size_t num_modules = target_modules.GetSize();
+ for (size_t i = 0; i < num_modules; ++i)
+ {
+ Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked(i);
+
+ SymbolContextList sc_list;
+ const bool include_symbols = true;
+ const bool append = true;
+ const bool include_inlines = true;
+
+ size_t num_matches = module_pointer->FindFunctions(ConstString("__asan_get_alloc_stack"), NULL, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
+
+ if (num_matches)
+ {
+ found_asan_runtime = true;
+ break;
+ }
+ }
+
+ if (! found_asan_runtime)
+ return MemoryHistorySP();
+
+ return MemoryHistorySP(new MemoryHistoryASan(process_sp));
+}
+
+void
+MemoryHistoryASan::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "ASan memory history provider.",
+ CreateInstance);
+}
+
+void
+MemoryHistoryASan::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+ConstString
+MemoryHistoryASan::GetPluginNameStatic()
+{
+ static ConstString g_name("asan");
+ return g_name;
+}
+
+MemoryHistoryASan::MemoryHistoryASan(const ProcessSP &process_sp)
+{
+ this->m_process_sp = process_sp;
+}
+
+const char *
+memory_history_asan_command_format = R"(
+ struct t {
+ void *alloc_trace[256];
+ size_t alloc_count;
+ int alloc_tid;
+
+ void *free_trace[256];
+ size_t free_count;
+ int free_tid;
+ } t;
+
+ t.alloc_count = ((size_t (*) (void *, void **, size_t, int *))__asan_get_alloc_stack)((void *)0x%)" PRIx64 R"(, t.alloc_trace, 256, &t.alloc_tid);
+ t.free_count = ((size_t (*) (void *, void **, size_t, int *))__asan_get_free_stack)((void *)0x%)" PRIx64 R"(, t.free_trace, 256, &t.free_tid);
+
+ t;
+)";
+
+static void CreateHistoryThreadFromValueObject(ProcessSP process_sp, ValueObjectSP return_value_sp, const char *type, const char *thread_name, HistoryThreads & result)
+{
+ std::string count_path = "." + std::string(type) + "_count";
+ std::string tid_path = "." + std::string(type) + "_tid";
+ std::string trace_path = "." + std::string(type) + "_trace";
+
+ int count = return_value_sp->GetValueForExpressionPath(count_path.c_str())->GetValueAsUnsigned(0);
+ tid_t tid = return_value_sp->GetValueForExpressionPath(tid_path.c_str())->GetValueAsUnsigned(0);
+
+ if (count <= 0)
+ return;
+
+ ValueObjectSP trace_sp = return_value_sp->GetValueForExpressionPath(trace_path.c_str());
+
+ std::vector<lldb::addr_t> pcs;
+ for (int i = 0; i < count; i++)
+ {
+ addr_t pc = trace_sp->GetChildAtIndex(i, true)->GetValueAsUnsigned(0);
+ if (pc == 0 || pc == 1 || pc == LLDB_INVALID_ADDRESS)
+ continue;
+ pcs.push_back(pc);
+ }
+
+ HistoryThread *history_thread = new HistoryThread(*process_sp, tid, pcs, 0, false);
+ ThreadSP new_thread_sp(history_thread);
+ // let's use thread name for the type of history thread, since history threads don't have names anyway
+ history_thread->SetThreadName(thread_name);
+ // Save this in the Process' ExtendedThreadList so a strong pointer retains the object
+ process_sp->GetExtendedThreadList().AddThread (new_thread_sp);
+ result.push_back(new_thread_sp);
+}
+
+#define GET_STACK_FUNCTION_TIMEOUT_USEC 2*1000*1000
+
+HistoryThreads
+MemoryHistoryASan::GetHistoryThreads(lldb::addr_t address)
+{
+ ProcessSP process_sp = m_process_sp;
+ ThreadSP thread_sp = m_process_sp->GetThreadList().GetSelectedThread();
+ StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
+
+ if (!frame_sp)
+ {
+ return HistoryThreads();
+ }
+
+ ExecutionContext exe_ctx (frame_sp);
+ ValueObjectSP return_value_sp;
+ StreamString expr;
+ expr.Printf(memory_history_asan_command_format, address, address);
+
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError(true);
+ options.SetTryAllThreads(true);
+ options.SetStopOthers(true);
+ options.SetIgnoreBreakpoints(true);
+ options.SetTimeoutUsec(GET_STACK_FUNCTION_TIMEOUT_USEC);
+
+ if (m_process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), return_value_sp, options) != eExpressionCompleted)
+ {
+ return HistoryThreads();
+ }
+ if (!return_value_sp)
+ {
+ return HistoryThreads();
+ }
+
+ HistoryThreads result;
+
+ CreateHistoryThreadFromValueObject(process_sp, return_value_sp, "alloc", "Memory allocated at", result);
+ CreateHistoryThreadFromValueObject(process_sp, return_value_sp, "free", "Memory deallocated at", result);
+
+ return result;
+}
diff --git a/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h b/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h
new file mode 100644
index 000000000000..5307e0b34081
--- /dev/null
+++ b/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h
@@ -0,0 +1,62 @@
+//===-- MemoryHistoryASan.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_MemoryHistoryASan_h_
+#define liblldb_MemoryHistoryASan_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/MemoryHistory.h"
+#include "lldb/Target/Process.h"
+
+namespace lldb_private {
+
+class MemoryHistoryASan : public lldb_private::MemoryHistory
+{
+public:
+
+ static lldb::MemoryHistorySP
+ CreateInstance (const lldb::ProcessSP &process_sp);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ virtual
+ ~MemoryHistoryASan () {}
+
+ virtual lldb_private::ConstString
+ GetPluginName() { return GetPluginNameStatic(); }
+
+ virtual uint32_t
+ GetPluginVersion() { return 1; }
+
+ virtual lldb_private::HistoryThreads
+ GetHistoryThreads(lldb::addr_t address);
+
+private:
+
+ MemoryHistoryASan(const lldb::ProcessSP &process_sp);
+
+ lldb::ProcessSP m_process_sp;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_MemoryHistoryASan_h_
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
index 0263c23ce307..1e2a0c721ff6 100644
--- a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
+++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -9,7 +9,7 @@
#include "ObjectContainerBSDArchive.h"
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__ANDROID_NDK__)
// Defines from ar, missing on Windows
#define ARMAG "!<arch>\n"
#define SARMAG 8
diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
index f027294b7c57..12392c24407b 100644
--- a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
+++ b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
@@ -173,6 +173,12 @@ ELFHeader::GetRelocationJumpSlotType() const
default:
assert(false && "architecture not supported");
break;
+ case EM_PPC:
+ slot = R_PPC_JMP_SLOT;
+ break;
+ case EM_PPC64:
+ slot = R_PPC64_JMP_SLOT;
+ break;
case EM_386:
case EM_486:
slot = R_386_JUMP_SLOT;
@@ -189,6 +195,9 @@ ELFHeader::GetRelocationJumpSlotType() const
case EM_AARCH64:
slot = R_AARCH64_JUMP_SLOT;
break;
+ case EM_MIPS:
+ slot = R_MIPS_JUMP_SLOT;
+ break;
}
return slot;
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index d86aee78947f..e7bf20e18008 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -267,10 +267,14 @@ kalimbaVariantFromElfFlags(const elf::elf_word e_flags)
{
// TODO(mg11) Support more variants
case 10:
- kal_arch_variant = 3;
+ kal_arch_variant = llvm::Triple::KalimbaSubArch_v3;
break;
case 14:
- kal_arch_variant = 4;
+ kal_arch_variant = llvm::Triple::KalimbaSubArch_v4;
+ break;
+ case 17:
+ case 20:
+ kal_arch_variant = llvm::Triple::KalimbaSubArch_v5;
break;
default:
break;
@@ -287,6 +291,34 @@ subTypeFromElfHeader(const elf::ELFHeader& header)
LLDB_INVALID_CPUTYPE;
}
+//! The kalimba toolchain identifies a code section as being
+//! one with the SHT_PROGBITS set in the section sh_type and the top
+//! bit in the 32-bit address field set.
+static lldb::SectionType
+kalimbaSectionType(
+ const elf::ELFHeader& header,
+ const elf::ELFSectionHeader& sect_hdr)
+{
+ if (llvm::ELF::EM_CSR_KALIMBA != header.e_machine)
+ {
+ return eSectionTypeOther;
+ }
+
+ if (llvm::ELF::SHT_NOBITS == sect_hdr.sh_type)
+ {
+ return eSectionTypeZeroFill;
+ }
+
+ if (llvm::ELF::SHT_PROGBITS == sect_hdr.sh_type)
+ {
+ const lldb::addr_t KAL_CODE_BIT = 1 << 31;
+ return KAL_CODE_BIT & sect_hdr.sh_addr ?
+ eSectionTypeCode : eSectionTypeData;
+ }
+
+ return eSectionTypeOther;
+}
+
// Arbitrary constant used as UUID prefix for core files.
const uint32_t
ObjectFileELF::g_core_uuid_magic(0xE210C);
@@ -826,6 +858,38 @@ ObjectFileELF::GetAddressByteSize() const
return m_data.GetAddressByteSize();
}
+// Top 16 bits of the `Symbol` flags are available.
+#define ARM_ELF_SYM_IS_THUMB (1 << 16)
+
+AddressClass
+ObjectFileELF::GetAddressClass (addr_t file_addr)
+{
+ auto res = ObjectFile::GetAddressClass (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;
+
+ // 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;
+
+ return res;
+}
+
size_t
ObjectFileELF::SectionIndex(const SectionHeaderCollIter &I)
{
@@ -1560,6 +1624,20 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list)
break;
}
+ if (eSectionTypeOther == sect_type)
+ {
+ // the kalimba toolchain assumes that ELF section names are free-form. It does
+ // supports linkscripts which (can) give rise to various arbitarily named
+ // sections being "Code" or "Data".
+ sect_type = kalimbaSectionType(m_header, header);
+ }
+
+ const uint32_t target_bytes_size =
+ (eSectionTypeData == sect_type || eSectionTypeZeroFill == sect_type) ?
+ m_arch_spec.GetDataByteSize() :
+ eSectionTypeCode == sect_type ?
+ m_arch_spec.GetCodeByteSize() : 1;
+
elf::elf_xword log2align = (header.sh_addralign==0)
? 0
: llvm::Log2_64(header.sh_addralign);
@@ -1573,7 +1651,8 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list)
header.sh_offset, // Offset of this section in the file.
file_size, // Size of the section as found in the file.
log2align, // Alignment of the section
- header.sh_flags)); // Flags for this section.
+ header.sh_flags, // Flags for this section.
+ target_bytes_size));// Number of host bytes per target byte
if (is_thread_specific)
section_sp->SetIsThreadSpecific (is_thread_specific);
@@ -1645,6 +1724,7 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
static ConstString rodata1_section_name(".rodata1");
static ConstString data2_section_name(".data1");
static ConstString bss_section_name(".bss");
+ static ConstString opd_section_name(".opd"); // For ppc64
//StreamFile strm(stdout, false);
unsigned i;
@@ -1746,6 +1826,48 @@ 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)
+ {
+ // 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;
+
+ // 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)
+ {
+ // 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 the symbol section we've found has no data (SHT_NOBITS), then check the module section
// list. This can happen if we're parsing the debug file and it has no .text section, for example.
if (symbol_section_sp && (symbol_section_sp->GetFileSize() == 0))
@@ -1766,12 +1888,15 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
}
}
- uint64_t symbol_value = symbol.st_value;
+ // 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;
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;
+ 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;
+
Symbol dc_symbol(
i + start_id, // ID is the original symbol table index.
symbol_name, // Symbol name.
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index 6b036af7aeff..b10dfb532cd0 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -133,6 +133,9 @@ public:
virtual uint32_t
GetAddressByteSize() const;
+ virtual lldb::AddressClass
+ GetAddressClass (lldb::addr_t file_addr);
+
virtual lldb_private::Symtab *
GetSymtab();
diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
index 7aa940a530b4..3b38a5819934 100644
--- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
+++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
@@ -32,7 +32,7 @@
using namespace lldb;
using namespace lldb_private;
-Platform *
+PlatformSP
PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
{
// The only time we create an instance is when we are creating a remote
@@ -84,8 +84,8 @@ PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
}
}
if (create)
- return new PlatformFreeBSD (is_host);
- return NULL;
+ return PlatformSP(new PlatformFreeBSD (is_host));
+ return PlatformSP();
}
@@ -124,7 +124,7 @@ PlatformFreeBSD::Initialize ()
// Force a host flag to true for the default platform object.
PlatformSP default_platform_sp (new PlatformFreeBSD(true));
default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
- Platform::SetDefaultPlatform (default_platform_sp);
+ Platform::SetHostPlatform (default_platform_sp);
#endif
PluginManager::RegisterPlugin(PlatformFreeBSD::GetPluginNameStatic(false),
PlatformFreeBSD::GetDescriptionStatic(false),
@@ -180,8 +180,7 @@ PlatformFreeBSD::RunShellCommand (const char *command,
Error
-PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
- const ArchSpec &exe_arch,
+PlatformFreeBSD::ResolveExecutable (const ModuleSpec &module_spec,
lldb::ModuleSP &exe_module_sp,
const FileSpecList *module_search_paths_ptr)
{
@@ -189,35 +188,33 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
// Nothing special to do here, just use the actual file and architecture
char exe_path[PATH_MAX];
- FileSpec resolved_exe_file (exe_file);
+ ModuleSpec resolved_module_spec(module_spec);
if (IsHost())
{
- // If we have "ls" as the exe_file, resolve the executable location based on
+ // If we have "ls" as the module_spec's file, resolve the executable location based on
// the current path variables
- if (!resolved_exe_file.Exists())
+ if (!resolved_module_spec.GetFileSpec().Exists())
{
- exe_file.GetPath(exe_path, sizeof(exe_path));
- resolved_exe_file.SetFile(exe_path, true);
+ module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
+ resolved_module_spec.GetFileSpec().SetFile(exe_path, true);
}
- if (!resolved_exe_file.Exists())
- resolved_exe_file.ResolveExecutableLocation ();
+ if (!resolved_module_spec.GetFileSpec().Exists())
+ resolved_module_spec.GetFileSpec().ResolveExecutableLocation ();
- if (resolved_exe_file.Exists())
+ if (resolved_module_spec.GetFileSpec().Exists())
error.Clear();
else
{
- exe_file.GetPath(exe_path, sizeof(exe_path));
- error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path);
+ error.SetErrorStringWithFormat("unable to find executable for '%s'", resolved_module_spec.GetFileSpec().GetPath().c_str());
}
}
else
{
if (m_remote_platform_sp)
{
- error = m_remote_platform_sp->ResolveExecutable (exe_file,
- exe_arch,
+ error = m_remote_platform_sp->ResolveExecutable (module_spec,
exe_module_sp,
module_search_paths_ptr);
}
@@ -226,25 +223,24 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
// We may connect to a process and use the provided executable (Don't use local $PATH).
// Resolve any executable within a bundle on MacOSX
- Host::ResolveExecutableInBundle (resolved_exe_file);
+ Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
- if (resolved_exe_file.Exists()) {
+ if (resolved_module_spec.GetFileSpec().Exists())
+ {
error.Clear();
}
else
{
- exe_file.GetPath(exe_path, sizeof(exe_path));
- error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path);
+ error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", resolved_module_spec.GetFileSpec().GetPath().c_str());
}
}
}
if (error.Success())
{
- ModuleSpec module_spec (resolved_exe_file, exe_arch);
- if (module_spec.GetArchitecture().IsValid())
+ if (resolved_module_spec.GetArchitecture().IsValid())
{
- error = ModuleList::GetSharedModule (module_spec,
+ error = ModuleList::GetSharedModule (resolved_module_spec,
exe_module_sp,
module_search_paths_ptr,
NULL,
@@ -254,8 +250,8 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
{
exe_module_sp.reset();
error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s",
- exe_file.GetPath().c_str(),
- exe_arch.GetArchitectureName());
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ resolved_module_spec.GetArchitecture().GetArchitectureName());
}
}
else
@@ -264,10 +260,9 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
// the architectures that we should be using (in the correct order)
// and see if we can find a match that way
StreamString arch_names;
- ArchSpec platform_arch;
- for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx)
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
{
- error = ModuleList::GetSharedModule (module_spec,
+ error = ModuleList::GetSharedModule (resolved_module_spec,
exe_module_sp,
module_search_paths_ptr,
NULL,
@@ -283,21 +278,21 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
if (idx > 0)
arch_names.PutCString (", ");
- arch_names.PutCString (platform_arch.GetArchitectureName());
+ arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName());
}
if (error.Fail() || !exe_module_sp)
{
- if (exe_file.Readable())
+ if (resolved_module_spec.GetFileSpec().Readable())
{
error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
- exe_file.GetPath().c_str(),
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
GetPluginName().GetCString(),
arch_names.GetString().c_str());
}
else
{
- error.SetErrorStringWithFormat("'%s' is not readable", exe_file.GetPath().c_str());
+ error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
}
}
}
@@ -326,6 +321,13 @@ PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite
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 (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
@@ -404,7 +406,7 @@ PlatformFreeBSD::ConnectRemote (Args& args)
else
{
if (!m_remote_platform_sp)
- m_remote_platform_sp = Platform::Create ("remote-gdb-server", error);
+ m_remote_platform_sp = Platform::Create (ConstString("remote-gdb-server"), error);
if (m_remote_platform_sp)
{
@@ -507,7 +509,6 @@ lldb::ProcessSP
PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
Debugger &debugger,
Target *target,
- Listener &listener,
Error &error)
{
lldb::ProcessSP process_sp;
@@ -535,7 +536,7 @@ PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
// 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 (listener, "gdb-remote", NULL);
+ process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
if (process_sp)
error = process_sp->Attach (attach_info);
@@ -544,7 +545,7 @@ PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
else
{
if (m_remote_platform_sp)
- process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error);
+ process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error);
else
error.SetErrorString ("the platform is not currently connected");
}
diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
index 62958a08a9e0..ce3f8cfad976 100644
--- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
+++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
@@ -24,7 +24,7 @@ public:
//------------------------------------------------------------
// Class functions
//------------------------------------------------------------
- static lldb_private::Platform*
+ static lldb::PlatformSP
CreateInstance (bool force, const lldb_private::ArchSpec *arch);
static void
@@ -80,8 +80,7 @@ public:
uint32_t timeout_sec);
virtual lldb_private::Error
- ResolveExecutable (const lldb_private::FileSpec &exe_file,
- const lldb_private::ArchSpec &arch,
+ ResolveExecutable (const lldb_private::ModuleSpec &module_spec,
lldb::ModuleSP &module_sp,
const lldb_private::FileSpecList *module_search_paths_ptr);
@@ -135,7 +134,6 @@ public:
Attach(lldb_private::ProcessAttachInfo &attach_info,
lldb_private::Debugger &debugger,
lldb_private::Target *target,
- lldb_private::Listener &listener,
lldb_private::Error &error);
// FreeBSD processes can not be launched by spawning and attaching.
diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
index cc4c693e1b43..b1be0f5b1fe1 100644
--- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
+++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
@@ -15,7 +15,9 @@
// Project includes
#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileCache.h"
@@ -330,8 +332,14 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source,
error = source_file.Read(buffer_sp->GetBytes(), bytes_read);
if (bytes_read)
{
- WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error);
- offset += bytes_read;
+ const uint64_t bytes_written = WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error);
+ offset += bytes_written;
+ if (bytes_written != bytes_read)
+ {
+ // We didn't write the correct numbe of bytes, so adjust
+ // the file position in the source file we are reading from...
+ source_file.SeekFromStart(offset);
+ }
}
else
break;
@@ -343,6 +351,18 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source,
// std::string dst_path (destination.GetPath());
// if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
// return Error("unable to perform chown");
+
+
+ uint64_t src_md5[2];
+ uint64_t dst_md5[2];
+
+ if (FileSystem::CalculateMD5 (source, src_md5[0], src_md5[1]) && CalculateMD5 (destination, dst_md5[0], dst_md5[1]))
+ {
+ if (src_md5[0] != dst_md5[0] || src_md5[1] != dst_md5[1])
+ {
+ error.SetErrorString("md5 checksum of installed file doesn't match, installation failed");
+ }
+ }
return error;
}
return Platform::PutFile(source,destination,uid,gid);
@@ -616,6 +636,18 @@ PlatformPOSIX::GetRemoteOSBuildString (std::string &s)
return false;
}
+size_t
+PlatformPOSIX::GetEnvironment (StringList &env)
+{
+ if (IsRemote())
+ {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetEnvironment(env);
+ return 0;
+ }
+ return Host::GetEnvironment(env);
+}
+
bool
PlatformPOSIX::GetRemoteOSKernelDescription (std::string &s)
{
@@ -681,7 +713,7 @@ PlatformPOSIX::ConnectRemote (Args& args)
else
{
if (!m_remote_platform_sp)
- m_remote_platform_sp = Platform::Create ("remote-gdb-server", error);
+ m_remote_platform_sp = Platform::Create (ConstString("remote-gdb-server"), error);
if (m_remote_platform_sp && error.Success())
error = m_remote_platform_sp->ConnectRemote (args);
@@ -739,11 +771,97 @@ PlatformPOSIX::DisconnectRemote ()
return error;
}
+Error
+PlatformPOSIX::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
+PlatformPOSIX::Attach (ProcessAttachInfo &attach_info,
+ Debugger &debugger,
+ Target *target,
+ Error &error)
+{
+ lldb::ProcessSP process_sp;
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+
+ if (IsHost())
+ {
+ if (target == NULL)
+ {
+ TargetSP new_target_sp;
+
+ error = debugger.GetTargetList().CreateTarget (debugger,
+ NULL,
+ NULL,
+ false,
+ NULL,
+ new_target_sp);
+ target = new_target_sp.get();
+ if (log)
+ log->Printf ("PlatformPOSIX::%s created new target", __FUNCTION__);
+ }
+ else
+ {
+ error.Clear();
+ if (log)
+ log->Printf ("PlatformPOSIX::%s target already existed, setting target", __FUNCTION__);
+ }
+
+ if (target && error.Success())
+ {
+ debugger.GetTargetList().SetSelectedTarget(target);
+ 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>" );
+ }
+
+
+ process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), attach_info.GetProcessPluginName(), NULL);
+
+ if (process_sp)
+ {
+ // Set UnixSignals appropriately.
+ process_sp->SetUnixSignals (Host::GetUnixSignals ());
+
+ ListenerSP listener_sp (new Listener("lldb.PlatformPOSIX.attach.hijack"));
+ attach_info.SetHijackListener(listener_sp);
+ process_sp->HijackProcessEvents(listener_sp.get());
+ 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;
+}
+
lldb::ProcessSP
PlatformPOSIX::DebugProcess (ProcessLaunchInfo &launch_info,
Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new target, else use existing one
- Listener &listener,
Error &error)
{
ProcessSP process_sp;
@@ -754,12 +872,12 @@ PlatformPOSIX::DebugProcess (ProcessLaunchInfo &launch_info,
// We still need to reap it from lldb but if we let the monitor thread also set the exit status, we set up a
// race between debugserver & us for who will find out about the debugged process's death.
launch_info.GetFlags().Set(eLaunchFlagDontSetExitStatus);
- process_sp = Platform::DebugProcess (launch_info, debugger, target, listener, error);
+ process_sp = Platform::DebugProcess (launch_info, debugger, target, error);
}
else
{
if (m_remote_platform_sp)
- process_sp = m_remote_platform_sp->DebugProcess (launch_info, debugger, target, listener, error);
+ process_sp = m_remote_platform_sp->DebugProcess (launch_info, debugger, target, error);
else
error.SetErrorString ("the platform is not currently connected");
}
diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h
index 374e36495d88..aae415e6eefa 100644
--- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h
+++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h
@@ -31,8 +31,9 @@ public:
//------------------------------------------------------------
// lldb_private::Platform functions
//------------------------------------------------------------
- virtual lldb_private::OptionGroupOptions*
- GetConnectionOptions (lldb_private::CommandInterpreter& interpreter);
+ virtual lldb_private::OptionGroupOptions
+ *GetConnectionOptions(
+ lldb_private::CommandInterpreter &interpreter) override;
const char *
GetHostname () override;
@@ -47,47 +48,47 @@ public:
PutFile (const lldb_private::FileSpec& source,
const lldb_private::FileSpec& destination,
uint32_t uid = UINT32_MAX,
- uint32_t gid = UINT32_MAX);
+ uint32_t gid = UINT32_MAX) override;
virtual lldb::user_id_t
OpenFile (const lldb_private::FileSpec& file_spec,
uint32_t flags,
uint32_t mode,
- lldb_private::Error &error);
+ lldb_private::Error &error) override;
virtual bool
CloseFile (lldb::user_id_t fd,
- lldb_private::Error &error);
+ lldb_private::Error &error) override;
virtual uint64_t
ReadFile (lldb::user_id_t fd,
uint64_t offset,
void *dst,
uint64_t dst_len,
- lldb_private::Error &error);
+ lldb_private::Error &error) override;
virtual uint64_t
WriteFile (lldb::user_id_t fd,
uint64_t offset,
const void* src,
uint64_t src_len,
- lldb_private::Error &error);
+ lldb_private::Error &error) override;
virtual lldb::user_id_t
- GetFileSize (const lldb_private::FileSpec& file_spec);
+ GetFileSize (const lldb_private::FileSpec& file_spec) override;
virtual lldb_private::Error
- CreateSymlink(const char *src, const char *dst);
+ CreateSymlink(const char *src, const char *dst) override;
virtual lldb_private::Error
GetFile (const lldb_private::FileSpec& source,
- const lldb_private::FileSpec& destination);
+ const lldb_private::FileSpec& destination) override;
virtual lldb_private::ConstString
- GetRemoteWorkingDirectory();
+ GetRemoteWorkingDirectory() override;
virtual bool
- SetRemoteWorkingDirectory(const lldb_private::ConstString &path);
+ SetRemoteWorkingDirectory(const lldb_private::ConstString &path) override;
bool
GetRemoteOSVersion () override;
@@ -101,6 +102,9 @@ public:
lldb_private::ArchSpec
GetRemoteSystemArchitecture () override;
+ size_t
+ GetEnvironment (lldb_private::StringList &environment) override;
+
bool
IsConnected () const override;
@@ -110,40 +114,48 @@ public:
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
+ 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);
+ MakeDirectory (const char *path, uint32_t mode) override;
virtual lldb_private::Error
- GetFilePermissions (const char *path, uint32_t &file_permissions);
+ GetFilePermissions (const char *path, uint32_t &file_permissions) override;
virtual lldb_private::Error
- SetFilePermissions (const char *path, uint32_t file_permissions);
+ SetFilePermissions (const char *path, uint32_t file_permissions) override;
virtual bool
- GetFileExists (const lldb_private::FileSpec& file_spec);
+ GetFileExists (const lldb_private::FileSpec& file_spec) override;
virtual lldb_private::Error
- Unlink (const char *path);
+ Unlink (const char *path) override;
+
+ lldb_private::Error
+ LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info) override;
+
+ 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) override;
lldb::ProcessSP
DebugProcess (lldb_private::ProcessLaunchInfo &launch_info,
lldb_private::Debugger &debugger,
lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one
- lldb_private::Listener &listener,
lldb_private::Error &error) override;
virtual std::string
- GetPlatformSpecificConnectionInformation();
+ GetPlatformSpecificConnectionInformation() override;
virtual bool
CalculateMD5 (const lldb_private::FileSpec& file_spec,
uint64_t &low,
- uint64_t &high);
+ uint64_t &high) override;
virtual void
- CalculateTrapHandlerSymbolNames ();
+ CalculateTrapHandlerSymbolNames () override;
lldb_private::Error
ConnectRemote (lldb_private::Args& args) override;
diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
index 05fbc5101278..43eae4d906ec 100644
--- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
+++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -16,14 +16,15 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Target/Process.h"
@@ -56,7 +57,7 @@ PlatformRemoteGDBServer::Terminate ()
}
}
-Platform*
+PlatformSP
PlatformRemoteGDBServer::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
{
bool create = force;
@@ -65,8 +66,8 @@ PlatformRemoteGDBServer::CreateInstance (bool force, const lldb_private::ArchSpe
create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified();
}
if (create)
- return new PlatformRemoteGDBServer ();
- return NULL;
+ return PlatformSP(new PlatformRemoteGDBServer());
+ return PlatformSP();
}
@@ -100,14 +101,13 @@ PlatformRemoteGDBServer::GetDescription ()
}
Error
-PlatformRemoteGDBServer::ResolveExecutable (const FileSpec &exe_file,
- const ArchSpec &exe_arch,
+PlatformRemoteGDBServer::ResolveExecutable (const ModuleSpec &module_spec,
lldb::ModuleSP &exe_module_sp,
const FileSpecList *module_search_paths_ptr)
{
Error error;
//error.SetErrorString ("PlatformRemoteGDBServer::ResolveExecutable() is unimplemented");
- if (m_gdb_client.GetFileExists(exe_file))
+ if (m_gdb_client.GetFileExists(module_spec.GetFileSpec()))
return error;
// TODO: get the remote end to somehow resolve this file
error.SetErrorString("file not found on remote end");
@@ -421,7 +421,6 @@ 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::Listener &listener,
lldb_private::Error &error)
{
lldb::ProcessSP process_sp;
@@ -473,7 +472,7 @@ PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_i
// The darwin always currently uses the GDB remote debugger plug-in
// so even when debugging locally we are debugging remotely!
- process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
+ process_sp = target->CreateProcess (launch_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
if (process_sp)
{
@@ -488,10 +487,16 @@ PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_i
port + port_offset);
assert (connect_url_len < (int)sizeof(connect_url));
error = process_sp->ConnectRemote (NULL, connect_url);
+ // Retry the connect remote one time...
+ if (error.Fail())
+ error = process_sp->ConnectRemote (NULL, connect_url);
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);
+ }
}
}
}
@@ -509,7 +514,6 @@ lldb::ProcessSP
PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new target, else use existing one
- Listener &listener,
Error &error)
{
lldb::ProcessSP process_sp;
@@ -561,7 +565,7 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
// The darwin always currently uses the GDB remote debugger plug-in
// so even when debugging locally we are debugging remotely!
- process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
+ process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
if (process_sp)
{
diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
index e236e97c8bb3..90b16b8b8fa9 100644
--- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
+++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
@@ -29,7 +29,7 @@ public:
static void
Terminate ();
- static lldb_private::Platform*
+ static lldb::PlatformSP
CreateInstance (bool force, const lldb_private::ArchSpec *arch);
static lldb_private::ConstString
@@ -64,8 +64,7 @@ public:
// lldb_private::Platform functions
//------------------------------------------------------------
virtual lldb_private::Error
- ResolveExecutable (const lldb_private::FileSpec &exe_file,
- const lldb_private::ArchSpec &arch,
+ ResolveExecutable (const lldb_private::ModuleSpec &module_spec,
lldb::ModuleSP &module_sp,
const lldb_private::FileSpecList *module_search_paths_ptr);
@@ -92,14 +91,12 @@ public:
DebugProcess (lldb_private::ProcessLaunchInfo &launch_info,
lldb_private::Debugger &debugger,
lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one
- lldb_private::Listener &listener,
lldb_private::Error &error);
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::Listener &listener,
lldb_private::Error &error);
virtual bool
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
index 4b488444de1e..5a0b5ed14194 100644
--- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
+++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -258,8 +258,7 @@ ProcessFreeBSD::SendMessage(const ProcessMessage &message)
case ProcessMessage::eLimboMessage:
case ProcessMessage::eExitMessage:
- m_exit_status = message.GetExitStatus();
- SetExitStatus(m_exit_status, NULL);
+ SetExitStatus(message.GetExitStatus(), NULL);
break;
case ProcessMessage::eSignalMessage:
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
index 63439b155111..84e35ba22644 100644
--- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -25,6 +25,7 @@
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/PseudoTerminal.h"
@@ -112,6 +113,7 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data,
log->Printf("PT_GETREGS: ax=0x%lx", 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';
@@ -119,6 +121,7 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data,
for (int i = 0; i <= 7; i++)
log->Printf("PT_%cETDBREGS: dr[%d]=0x%lx", setget, i, r->dr[i]);
}
+#endif
}
return result;
@@ -309,9 +312,14 @@ ReadRegOperation::Execute(ProcessMonitor *monitor)
if ((rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)&regs, 0)) < 0) {
m_result = false;
} else {
- if (m_size == sizeof(uintptr_t))
- m_value = *(uintptr_t *)(((caddr_t)&regs) + m_offset);
- else
+ // 'struct reg' contains only 32- or 64-bit register values. Punt on
+ // others. Also, not all entries may be uintptr_t sized, such as 32-bit
+ // processes on powerpc64 (probably the same for i386 on amd64)
+ if (m_size == sizeof(uint32_t))
+ m_value = *(uint32_t *)(((caddr_t)&regs) + m_offset);
+ else if (m_size == sizeof(uint64_t))
+ m_value = *(uint64_t *)(((caddr_t)&regs) + m_offset);
+ else
memcpy(&m_value, (((caddr_t)&regs) + m_offset), m_size);
m_result = true;
}
@@ -810,8 +818,6 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
const lldb_private::ProcessLaunchInfo & /* launch_info */,
lldb_private::Error &error)
: m_process(static_cast<ProcessFreeBSD *>(process)),
- m_operation_thread(LLDB_INVALID_HOST_THREAD),
- m_monitor_thread(LLDB_INVALID_HOST_THREAD),
m_pid(LLDB_INVALID_PROCESS_ID),
m_terminal_fd(-1),
m_operation(0)
@@ -852,7 +858,7 @@ WAIT_AGAIN:
// Finally, start monitoring the child process for change in state.
m_monitor_thread = Host::StartMonitoringChildProcess(
ProcessMonitor::MonitorCallback, this, GetPID(), true);
- if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ if (!m_monitor_thread.IsJoinable())
{
error.SetErrorToGenericError();
error.SetErrorString("Process launch failed.");
@@ -864,8 +870,6 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
lldb::pid_t pid,
lldb_private::Error &error)
: m_process(static_cast<ProcessFreeBSD *>(process)),
- m_operation_thread(LLDB_INVALID_HOST_THREAD),
- m_monitor_thread(LLDB_INVALID_HOST_THREAD),
m_pid(pid),
m_terminal_fd(-1),
m_operation(0)
@@ -904,7 +908,7 @@ WAIT_AGAIN:
// Finally, start monitoring the child process for change in state.
m_monitor_thread = Host::StartMonitoringChildProcess(
ProcessMonitor::MonitorCallback, this, GetPID(), true);
- if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ if (!m_monitor_thread.IsJoinable())
{
error.SetErrorToGenericError();
error.SetErrorString("Process attach failed.");
@@ -924,11 +928,10 @@ ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Error &error)
{
static const char *g_thread_name = "lldb.process.freebsd.operation";
- if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ if (m_operation_thread.IsJoinable())
return;
- m_operation_thread =
- Host::ThreadCreate(g_thread_name, LaunchOpThread, args, &error);
+ m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, LaunchOpThread, args, &error);
}
void *
@@ -1101,11 +1104,10 @@ ProcessMonitor::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error
{
static const char *g_thread_name = "lldb.process.freebsd.operation";
- if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ if (m_operation_thread.IsJoinable())
return;
- m_operation_thread =
- Host::ThreadCreate(g_thread_name, AttachOpThread, args, &error);
+ m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, AttachOpThread, args, &error);
}
void *
@@ -1113,14 +1115,13 @@ ProcessMonitor::AttachOpThread(void *arg)
{
AttachArgs *args = static_cast<AttachArgs*>(arg);
- if (!Attach(args))
- return NULL;
+ Attach(args);
ServeOperation(args);
return NULL;
}
-bool
+void
ProcessMonitor::Attach(AttachArgs *args)
{
lldb::pid_t pid = args->m_pid;
@@ -1132,27 +1133,24 @@ ProcessMonitor::Attach(AttachArgs *args)
{
args->m_error.SetErrorToGenericError();
args->m_error.SetErrorString("Attaching to process 1 is not allowed.");
- goto FINISH;
+ return;
}
// Attach to the requested process.
if (PTRACE(PT_ATTACH, pid, NULL, 0) < 0)
{
args->m_error.SetErrorToErrno();
- goto FINISH;
+ return;
}
int status;
if ((status = waitpid(pid, NULL, 0)) < 0)
{
args->m_error.SetErrorToErrno();
- goto FINISH;
+ return;
}
process.SendMessage(ProcessMessage::Attach(pid));
-
-FINISH:
- return args->m_error.Success();
}
size_t
@@ -1714,13 +1712,11 @@ ProcessMonitor::DupDescriptor(const char *path, int fd, int flags)
void
ProcessMonitor::StopMonitoringChildProcess()
{
- lldb::thread_result_t thread_result;
-
- if (IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ if (m_monitor_thread.IsJoinable())
{
- Host::ThreadCancel(m_monitor_thread, NULL);
- Host::ThreadJoin(m_monitor_thread, &thread_result, NULL);
- m_monitor_thread = LLDB_INVALID_HOST_THREAD;
+ m_monitor_thread.Cancel();
+ m_monitor_thread.Join(nullptr);
+ m_monitor_thread.Reset();
}
}
@@ -1764,12 +1760,10 @@ ProcessMonitor::WaitForInitialTIDStop(lldb::tid_t tid)
void
ProcessMonitor::StopOpThread()
{
- lldb::thread_result_t result;
-
- if (!IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ if (!m_operation_thread.IsJoinable())
return;
- Host::ThreadCancel(m_operation_thread, NULL);
- Host::ThreadJoin(m_operation_thread, &result, NULL);
- m_operation_thread = LLDB_INVALID_HOST_THREAD;
+ m_operation_thread.Cancel();
+ m_operation_thread.Join(nullptr);
+ m_operation_thread.Reset();
}
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
index 314743b00754..935fd85ed37a 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/HostThread.h"
#include "lldb/Host/Mutex.h"
namespace lldb_private
@@ -212,8 +213,8 @@ public:
private:
ProcessFreeBSD *m_process;
- lldb::thread_t m_operation_thread;
- lldb::thread_t m_monitor_thread;
+ lldb_private::HostThread m_operation_thread;
+ lldb_private::HostThread m_monitor_thread;
lldb::pid_t m_pid;
int m_terminal_fd;
@@ -289,7 +290,7 @@ private:
static void *
AttachOpThread(void *args);
- static bool
+ static void
Attach(AttachArgs *args);
static void
diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/POSIX/POSIXThread.cpp
index d48f8f9dd307..1057585e1b2a 100644
--- a/source/Plugins/Process/POSIX/POSIXThread.cpp
+++ b/source/Plugins/Process/POSIX/POSIXThread.cpp
@@ -20,27 +20,30 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/State.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostNativeThread.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
+#include "llvm/ADT/SmallString.h"
#include "POSIXStopInfo.h"
#include "POSIXThread.h"
#include "ProcessPOSIX.h"
#include "ProcessPOSIXLog.h"
-#include "ProcessMonitor.h"
+#include "Plugins/Process/Linux/ProcessMonitor.h"
#include "RegisterContextPOSIXProcessMonitor_arm64.h"
#include "RegisterContextPOSIXProcessMonitor_mips64.h"
+#include "RegisterContextPOSIXProcessMonitor_powerpc.h"
#include "RegisterContextPOSIXProcessMonitor_x86.h"
-#include "RegisterContextLinux_arm64.h"
-#include "RegisterContextLinux_i386.h"
-#include "RegisterContextLinux_x86_64.h"
-#include "RegisterContextFreeBSD_i386.h"
-#include "RegisterContextFreeBSD_mips64.h"
-#include "RegisterContextFreeBSD_x86_64.h"
-
-#include "UnwindLLDB.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_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 "Plugins/Process/Utility/UnwindLLDB.h"
using namespace lldb;
using namespace lldb_private;
@@ -140,7 +143,9 @@ POSIXThread::GetName ()
{
if (!m_thread_name_valid)
{
- SetName(Host::GetThreadName(GetProcess()->GetID(), GetID()).c_str());
+ llvm::SmallString<32> thread_name;
+ HostNativeThread::GetName(GetID(), thread_name);
+ m_thread_name = thread_name.c_str();
m_thread_name_valid = true;
}
@@ -164,6 +169,14 @@ POSIXThread::GetRegisterContext()
case llvm::Triple::FreeBSD:
switch (target_arch.GetMachine())
{
+ case llvm::Triple::ppc:
+#ifndef __powerpc64__
+ reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch);
+ break;
+#endif
+ case llvm::Triple::ppc64:
+ reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch);
+ break;
case llvm::Triple::mips64:
reg_interface = new RegisterContextFreeBSD_mips64(target_arch);
break;
@@ -226,6 +239,14 @@ POSIXThread::GetRegisterContext()
m_reg_context_sp.reset(reg_ctx);
break;
}
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ {
+ RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx = new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0, reg_interface);
+ m_posix_thread = reg_ctx;
+ m_reg_context_sp.reset(reg_ctx);
+ break;
+ }
case llvm::Triple::x86:
case llvm::Triple::x86_64:
{
@@ -621,6 +642,8 @@ POSIXThread::GetRegisterIndexFromOffset(unsigned offset)
case llvm::Triple::aarch64:
case llvm::Triple::mips64:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
{
@@ -652,6 +675,8 @@ POSIXThread::GetRegisterName(unsigned reg)
case llvm::Triple::aarch64:
case llvm::Triple::mips64:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
name = GetRegisterContext()->GetRegisterName(reg);
diff --git a/source/Plugins/Process/POSIX/POSIXThread.h b/source/Plugins/Process/POSIX/POSIXThread.h
index 51d6645f209d..56dcccbfb0f9 100644
--- a/source/Plugins/Process/POSIX/POSIXThread.h
+++ b/source/Plugins/Process/POSIX/POSIXThread.h
@@ -17,7 +17,7 @@
// Other libraries and framework includes
#include "lldb/Target/Thread.h"
-#include "RegisterContextPOSIX.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX.h"
class ProcessMessage;
class ProcessMonitor;
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
index f340631c7d07..0e5ab5a8d8b1 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -16,6 +16,7 @@
// Other libraries and framework includes
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
#include "lldb/Host/FileSpec.h"
@@ -28,7 +29,7 @@
#include "ProcessPOSIX.h"
#include "ProcessPOSIXLog.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
-#include "ProcessMonitor.h"
+#include "Plugins/Process/Linux/ProcessMonitor.h"
#include "POSIXThread.h"
using namespace lldb;
@@ -140,8 +141,8 @@ ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid)
// Resolve the executable module
ModuleSP exe_module_sp;
FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
- error = platform_sp->ResolveExecutable(process_info.GetExecutableFile(),
- m_target.GetArchitecture(),
+ ModuleSpec exe_module_spec(process_info.GetExecutableFile(), m_target.GetArchitecture());
+ error = platform_sp->ResolveExecutable(exe_module_spec,
exe_module_sp,
executable_search_paths.GetSize() ? &executable_search_paths : NULL);
if (!error.Success())
@@ -176,9 +177,9 @@ ProcessPOSIX::WillLaunch(Module* module)
}
const char *
-ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const char *default_path)
+ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const char *default_path,
+ const char *dbg_pts_path)
{
- const char *pts_name = "/dev/pts/";
const char *path = NULL;
if (file_action)
@@ -190,11 +191,11 @@ ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const cha
// (/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 || ::strncmp(path, pts_name, ::strlen(pts_name)) == 0)
+ if (!path || (dbg_pts_path &&
+ ::strncmp(path, dbg_pts_path, ::strlen(dbg_pts_path)) == 0))
path = default_path;
}
}
-
return path;
}
@@ -224,14 +225,16 @@ ProcessPOSIX::DoLaunch (Module *module,
const char *stdout_path = NULL;
const char *stderr_path = NULL;
+ const char * dbg_pts_path = launch_info.GetPTY().GetSlaveName(NULL,0);
+
file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
- stdin_path = GetFilePath(file_action, stdin_path);
+ stdin_path = GetFilePath(file_action, stdin_path, dbg_pts_path);
file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
- stdout_path = GetFilePath(file_action, stdout_path);
+ stdout_path = GetFilePath(file_action, stdout_path, dbg_pts_path);
file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
- stderr_path = GetFilePath(file_action, stderr_path);
+ stderr_path = GetFilePath(file_action, stderr_path, dbg_pts_path);
m_monitor = new ProcessMonitor (this,
module,
@@ -338,6 +341,11 @@ ProcessPOSIX::DoDestroy()
{
assert(m_monitor);
m_exit_now = true;
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ error.SetErrorString("invalid process id");
+ return error;
+ }
if (!m_monitor->Kill())
{
error.SetErrorToErrno();
@@ -363,11 +371,11 @@ ProcessPOSIX::DoDidExec()
ProcessInstanceInfo process_info;
platform_sp->GetProcessInfo(GetID(), process_info);
ModuleSP exe_module_sp;
+ ModuleSpec exe_module_spec(process_info.GetExecutableFile(), target->GetArchitecture());
FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
- Error error = platform_sp->ResolveExecutable(process_info.GetExecutableFile(),
- target->GetArchitecture(),
- exe_module_sp,
- executable_search_paths.GetSize() ? &executable_search_paths : NULL);
+ Error error = platform_sp->ResolveExecutable(exe_module_spec,
+ exe_module_sp,
+ executable_search_paths.GetSize() ? &executable_search_paths : NULL);
if (!error.Success())
return;
target->SetExecutableModule(exe_module_sp, true);
@@ -432,8 +440,7 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message)
// FIXME: I'm not sure we need to do this.
if (message.GetTID() == GetID())
{
- m_exit_status = message.GetExitStatus();
- SetExitStatus(m_exit_status, NULL);
+ SetExitStatus(message.GetExitStatus(), NULL);
}
else if (!IsAThreadRunning())
SetPrivateState(eStateStopped);
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h
index 033accf17f29..f152356b3093 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.h
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h
@@ -42,104 +42,104 @@ public:
// Process protocol.
//------------------------------------------------------------------
virtual void
- Finalize();
+ Finalize() override;
virtual bool
- CanDebug(lldb_private::Target &target, bool plugin_specified_by_name);
+ CanDebug(lldb_private::Target &target, bool plugin_specified_by_name) override;
virtual lldb_private::Error
- WillLaunch(lldb_private::Module *module);
+ WillLaunch(lldb_private::Module *module) override;
virtual lldb_private::Error
- DoAttachToProcessWithID(lldb::pid_t pid);
+ DoAttachToProcessWithID(lldb::pid_t pid) override;
virtual lldb_private::Error
- DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info);
+ DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override;
virtual lldb_private::Error
DoLaunch (lldb_private::Module *exe_module,
- lldb_private::ProcessLaunchInfo &launch_info);
+ lldb_private::ProcessLaunchInfo &launch_info) override;
virtual void
- DidLaunch();
+ DidLaunch() override;
virtual lldb_private::Error
- DoResume();
+ DoResume() override;
virtual lldb_private::Error
- DoHalt(bool &caused_stop);
+ DoHalt(bool &caused_stop) override;
virtual lldb_private::Error
- DoDetach(bool keep_stopped) = 0;
+ DoDetach(bool keep_stopped) override = 0;
virtual lldb_private::Error
- DoSignal(int signal);
+ DoSignal(int signal) override;
virtual lldb_private::Error
- DoDestroy();
+ DoDestroy() override;
virtual void
- DoDidExec();
+ DoDidExec() override;
virtual void
- RefreshStateAfterStop();
+ RefreshStateAfterStop() override;
virtual bool
- IsAlive();
+ IsAlive() override;
virtual size_t
DoReadMemory(lldb::addr_t vm_addr,
void *buf,
size_t size,
- lldb_private::Error &error);
+ lldb_private::Error &error) override;
virtual size_t
DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
- lldb_private::Error &error);
+ lldb_private::Error &error) override;
virtual lldb::addr_t
DoAllocateMemory(size_t size, uint32_t permissions,
- lldb_private::Error &error);
+ lldb_private::Error &error) override;
virtual lldb_private::Error
- DoDeallocateMemory(lldb::addr_t ptr);
+ DoDeallocateMemory(lldb::addr_t ptr) override;
virtual size_t
GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site);
virtual lldb_private::Error
- EnableBreakpointSite(lldb_private::BreakpointSite *bp_site);
+ EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
virtual lldb_private::Error
- DisableBreakpointSite(lldb_private::BreakpointSite *bp_site);
+ DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
virtual lldb_private::Error
- EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+ EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override;
virtual lldb_private::Error
- DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+ DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override;
virtual lldb_private::Error
- GetWatchpointSupportInfo(uint32_t &num);
+ GetWatchpointSupportInfo(uint32_t &num) override;
virtual lldb_private::Error
- GetWatchpointSupportInfo(uint32_t &num, bool &after);
+ GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
virtual uint32_t
UpdateThreadListIfNeeded();
virtual bool
UpdateThreadList(lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list) = 0;
+ lldb_private::ThreadList &new_thread_list) override = 0;
virtual lldb::ByteOrder
GetByteOrder() const;
virtual lldb::addr_t
- GetImageInfoAddress();
+ GetImageInfoAddress() override;
virtual size_t
- PutSTDIN(const char *buf, size_t len, lldb_private::Error &error);
+ PutSTDIN(const char *buf, size_t len, lldb_private::Error &error) override;
const lldb::DataBufferSP
GetAuxvData () override;
@@ -154,7 +154,8 @@ public:
ProcessMonitor &
GetMonitor() { assert(m_monitor); return *m_monitor; }
- const char *GetFilePath(const lldb_private::FileAction *file_action, const char *default_path);
+ 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.
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp
index 9109cdb000ae..ec34d9e28161 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp
@@ -10,10 +10,10 @@
#include "lldb/Target/Thread.h"
#include "lldb/Core/RegisterValue.h"
-#include "RegisterContextPOSIX_arm64.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
#include "ProcessPOSIX.h"
#include "RegisterContextPOSIXProcessMonitor_arm64.h"
-#include "ProcessMonitor.h"
+#include "Plugins/Process/Linux/ProcessMonitor.h"
#define REG_CONTEXT_SIZE (GetGPRSize())
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp
index 9bfe236de139..6717d20da056 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp
@@ -10,10 +10,10 @@
#include "lldb/Target/Thread.h"
#include "lldb/Core/RegisterValue.h"
-#include "RegisterContextPOSIX_mips64.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
#include "ProcessPOSIX.h"
#include "RegisterContextPOSIXProcessMonitor_mips64.h"
-#include "ProcessMonitor.h"
+#include "Plugins/Process/Linux/ProcessMonitor.h"
using namespace lldb_private;
using namespace lldb;
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp
new file mode 100644
index 000000000000..b542db4779db
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp
@@ -0,0 +1,321 @@
+//===-- RegisterContextPOSIXProcessMonitor_powerpc.h ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Core/RegisterValue.h"
+
+#include "RegisterContextPOSIX_powerpc.h"
+#include "ProcessPOSIX.h"
+#include "RegisterContextPOSIXProcessMonitor_powerpc.h"
+#include "ProcessMonitor.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+#define REG_CONTEXT_SIZE (GetGPRSize())
+
+RegisterContextPOSIXProcessMonitor_powerpc::RegisterContextPOSIXProcessMonitor_powerpc(Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info)
+ : RegisterContextPOSIX_powerpc(thread, concrete_frame_idx, register_info)
+{
+}
+
+ProcessMonitor &
+RegisterContextPOSIXProcessMonitor_powerpc::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ReadGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ReadFPR()
+{
+ // XXX not yet implemented
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::WriteGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::WriteFPR()
+{
+ // XXX not yet implemented
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::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();
+ // Account for the fact that 32-bit targets on powerpc64 really use 64-bit
+ // registers in ptrace, but expose here 32-bit registers with a higher
+ // offset.
+ uint64_t offset = GetRegisterOffset(reg_to_write);
+ offset &= ~(sizeof(uintptr_t) - 1);
+ return monitor.WriteRegisterValue(m_thread.GetID(),
+ offset,
+ GetRegisterName(reg_to_write),
+ value_to_write);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::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
+ {
+ uint32_t full_reg = reg;
+ bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
+
+ if (is_subreg)
+ {
+ // Read the full aligned 64-bit register.
+ full_reg = reg_info->invalidate_regs[0];
+ }
+
+ bool success = ReadRegister(full_reg, value);
+
+ if (success)
+ {
+ // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
+ if (is_subreg && (reg_info->byte_offset & 0x1))
+ value.SetUInt64(value.GetAsUInt64() >> 8);
+
+ // If our return byte size was greater than the return value reg size, then
+ // use the type specified by reg_info rather than the uint64_t default
+ if (value.GetByteSize() > reg_info->byte_size)
+ value.SetType(reg_info);
+ }
+ return success;
+ }
+
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsGPR(reg))
+ return WriteRegister(reg, value);
+
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::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_powerpc, GetGPRSize());
+ dst += GetGPRSize();
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::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_powerpc, src, GetGPRSize());
+
+ if (WriteGPR())
+ {
+ src += GetGPRSize();
+ }
+ }
+ }
+ return success;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_powerpc::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_powerpc::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::HardwareSingleStep(bool enable)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::UpdateAfterBreakpoint()
+{
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ return true;
+}
+
+unsigned
+RegisterContextPOSIXProcessMonitor_powerpc::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers_powerpc; reg++)
+ {
+ if (GetRegisterInfo()[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers_powerpc && "Invalid register offset.");
+ return reg;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointHit(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ClearWatchpointHits()
+{
+ return false;
+}
+
+addr_t
+RegisterContextPOSIXProcessMonitor_powerpc::GetWatchpointAddress(uint32_t hw_index)
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointVacant(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_powerpc::NumSupportedHardwareWatchpoints()
+{
+ return 0;
+}
+
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h
new file mode 100644
index 000000000000..92a331285515
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h
@@ -0,0 +1,95 @@
+//===-- RegisterContextPOSIXProcessMonitor_powerpc.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_powerpc_H_
+#define liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
+
+class RegisterContextPOSIXProcessMonitor_powerpc:
+ public RegisterContextPOSIX_powerpc,
+ public POSIXBreakpointProtocol
+{
+public:
+ RegisterContextPOSIXProcessMonitor_powerpc(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_x86.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp
index e534f3b4f9d0..1956e4584fa9 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp
@@ -10,9 +10,13 @@
#include "lldb/Target/Thread.h"
#include "lldb/Core/RegisterValue.h"
-#include "ProcessPOSIX.h"
+#include "Plugins/Process/POSIX/ProcessPOSIX.h"
#include "RegisterContextPOSIXProcessMonitor_x86.h"
-#include "ProcessMonitor.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;
@@ -48,6 +52,7 @@ size_and_rw_bits(size_t size, bool read, bool write)
return (0x2 << 2) | rw;
default:
assert(0 && "invalid size, must be one of 1, 2, 4, or 8");
+ return 0; // Unreachable. Just to silence compiler.
}
}
diff --git a/source/Plugins/Process/Utility/ARMDefines.h b/source/Plugins/Process/Utility/ARMDefines.h
index 2c8ad3586af1..cfb33beb447a 100644
--- a/source/Plugins/Process/Utility/ARMDefines.h
+++ b/source/Plugins/Process/Utility/ARMDefines.h
@@ -45,7 +45,8 @@ typedef enum
#define COND_AL 0xE // Always (unconditional) Always (unconditional) Any
#define COND_UNCOND 0xF
-static inline const char *ARMCondCodeToString(uint32_t CC)
+static inline const char *
+ARMCondCodeToString(uint32_t CC)
{
switch (CC) {
default: assert(0 && "Unknown condition code");
@@ -67,6 +68,37 @@ static inline const char *ARMCondCodeToString(uint32_t CC)
}
}
+static inline bool
+ARMConditionPassed(const uint32_t condition, const uint32_t cpsr)
+{
+ const uint32_t cpsr_n = (cpsr >> 31) & 1u; // Negative condition code flag
+ const uint32_t cpsr_z = (cpsr >> 30) & 1u; // Zero condition code flag
+ const uint32_t cpsr_c = (cpsr >> 29) & 1u; // Carry condition code flag
+ const uint32_t cpsr_v = (cpsr >> 28) & 1u; // Overflow condition code flag
+
+ switch (condition) {
+ case COND_EQ: return (cpsr_z == 1);
+ case COND_NE: return (cpsr_z == 0);
+ case COND_CS: return (cpsr_c == 1);
+ case COND_CC: return (cpsr_c == 0);
+ case COND_MI: return (cpsr_n == 1);
+ case COND_PL: return (cpsr_n == 0);
+ case COND_VS: return (cpsr_v == 1);
+ case COND_VC: return (cpsr_v == 0);
+ case COND_HI: return ((cpsr_c == 1) && (cpsr_z == 0));
+ case COND_LS: return ((cpsr_c == 0) || (cpsr_z == 1));
+ case COND_GE: return (cpsr_n == cpsr_v);
+ case COND_LT: return (cpsr_n != cpsr_v);
+ case COND_GT: return ((cpsr_z == 0) && (cpsr_n == cpsr_v));
+ case COND_LE: return ((cpsr_z == 1) || (cpsr_n != cpsr_v));
+ case COND_AL:
+ case COND_UNCOND:
+ default:
+ return true;
+ }
+ return false;
+}
+
// Bit positions for CPSR
#define CPSR_T_POS 5
#define CPSR_F_POS 6
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
index 3507ccf92065..1088924bfeac 100644
--- a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -81,6 +81,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
else
{
Clear();
+ printf("error: register sets must have valid names\n");
return 0;
}
}
@@ -121,6 +122,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
if (reg_info.name == NULL)
{
Clear();
+ printf("error: registers must have valid names\n");
+ reg_info_dict.Dump();
return 0;
}
@@ -290,6 +293,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
if (!success)
{
Clear();
+ reg_info_dict.Dump();
return 0;
}
}
@@ -297,6 +301,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
if (bitsize == 0)
{
Clear();
+ printf("error: invalid or missing 'bitsize' key/value pair in register dictionary\n");
+ reg_info_dict.Dump();
return 0;
}
@@ -308,6 +314,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
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;
}
}
@@ -326,6 +334,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
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;
}
@@ -409,6 +419,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
else
{
Clear();
+ printf("error: items in the 'registers' array must be dictionaries\n");
+ regs.Dump();
return 0;
}
}
diff --git a/source/Plugins/Process/Utility/HistoryThread.cpp b/source/Plugins/Process/Utility/HistoryThread.cpp
index 590bb0162c8a..206b8290c5fd 100644
--- a/source/Plugins/Process/Utility/HistoryThread.cpp
+++ b/source/Plugins/Process/Utility/HistoryThread.cpp
@@ -39,7 +39,7 @@ HistoryThread::HistoryThread (lldb_private::Process &process,
m_originating_unique_thread_id (tid),
m_queue_id (LLDB_INVALID_QUEUE_ID)
{
- m_unwinder_ap.reset (new HistoryUnwind (*this, pcs, stop_id, stop_id_is_valid));
+ m_unwinder_ap.reset (new HistoryUnwind (*this, pcs, stop_id_is_valid));
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
log->Printf ("%p HistoryThread::HistoryThread",
diff --git a/source/Plugins/Process/Utility/HistoryThread.h b/source/Plugins/Process/Utility/HistoryThread.h
index f9a431d8340b..51173c626d71 100644
--- a/source/Plugins/Process/Utility/HistoryThread.h
+++ b/source/Plugins/Process/Utility/HistoryThread.h
@@ -101,6 +101,18 @@ public:
{
m_thread_name = name;
}
+
+ virtual const char *
+ GetName ()
+ {
+ return m_thread_name.c_str();
+ }
+
+ virtual void
+ SetName(const char *name)
+ {
+ m_thread_name = name;
+ }
protected:
virtual lldb::StackFrameListSP
diff --git a/source/Plugins/Process/Utility/HistoryUnwind.cpp b/source/Plugins/Process/Utility/HistoryUnwind.cpp
index f809ebedcfc8..14afcbee0b49 100644
--- a/source/Plugins/Process/Utility/HistoryUnwind.cpp
+++ b/source/Plugins/Process/Utility/HistoryUnwind.cpp
@@ -24,11 +24,9 @@ using namespace lldb_private;
HistoryUnwind::HistoryUnwind (Thread &thread,
std::vector<lldb::addr_t> pcs,
- uint32_t stop_id,
bool stop_id_is_valid) :
Unwind (thread),
m_pcs (pcs),
- m_stop_id (stop_id),
m_stop_id_is_valid (stop_id_is_valid)
{
}
diff --git a/source/Plugins/Process/Utility/HistoryUnwind.h b/source/Plugins/Process/Utility/HistoryUnwind.h
index 0661b8028608..733f93e1ff87 100644
--- a/source/Plugins/Process/Utility/HistoryUnwind.h
+++ b/source/Plugins/Process/Utility/HistoryUnwind.h
@@ -21,7 +21,7 @@ namespace lldb_private {
class HistoryUnwind : public lldb_private::Unwind
{
public:
- HistoryUnwind (Thread &thread, std::vector<lldb::addr_t> pcs, uint32_t stop_id, bool stop_id_is_valid);
+ HistoryUnwind (Thread &thread, std::vector<lldb::addr_t> pcs, bool stop_id_is_valid);
virtual ~HistoryUnwind ();
@@ -42,7 +42,6 @@ protected:
private:
std::vector<lldb::addr_t> m_pcs;
- uint32_t m_stop_id;
bool m_stop_id_is_valid;
};
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index 4a94457466be..7db83ae5467f 100644
--- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -98,13 +98,11 @@ lldb_private::InferiorCallMmap (Process *process,
ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
lldb::addr_t args[] = { addr, length, prot_arg, flags_arg, fd, offset };
- ThreadPlanCallFunction *call_function_thread_plan
- = new ThreadPlanCallFunction (*thread,
- mmap_range.GetBaseAddress(),
- clang_void_ptr_type,
- args,
- options);
- lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
+ mmap_range.GetBaseAddress(),
+ clang_void_ptr_type,
+ args,
+ options));
if (call_plan_sp)
{
StreamFile error_strm;
@@ -241,13 +239,11 @@ lldb_private::InferiorCall (Process *process,
ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
- ThreadPlanCallFunction *call_function_thread_plan
- = new ThreadPlanCallFunction (*thread,
- *address,
- clang_void_ptr_type,
- llvm::ArrayRef<addr_t>(),
- options);
- lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
+ *address,
+ clang_void_ptr_type,
+ llvm::ArrayRef<addr_t>(),
+ options));
if (call_plan_sp)
{
StreamString error_strm;
diff --git a/source/Plugins/Process/Utility/InstructionUtils.h b/source/Plugins/Process/Utility/InstructionUtils.h
index 813990095c49..6226fbc04b08 100644
--- a/source/Plugins/Process/Utility/InstructionUtils.h
+++ b/source/Plugins/Process/Utility/InstructionUtils.h
@@ -20,7 +20,7 @@ static inline uint64_t
Bits64 (const uint64_t bits, const uint32_t msbit, const uint32_t lsbit)
{
assert(msbit < 64 && lsbit <= msbit);
- return (bits >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1);
+ return (bits >> lsbit) & ((1ull << (msbit - lsbit + 1)) - 1);
}
// Return the bit field(s) from the most significant bit (msbit) to the
diff --git a/source/Plugins/Process/Utility/LinuxSignals.cpp b/source/Plugins/Process/Utility/LinuxSignals.cpp
index fb49df681cae..11a3eef23529 100644
--- a/source/Plugins/Process/Utility/LinuxSignals.cpp
+++ b/source/Plugins/Process/Utility/LinuxSignals.cpp
@@ -53,7 +53,7 @@ LinuxSignals::Reset()
AddSignal (24, "SIGXCPU", "XCPU", false, true , true , "CPU resource exceeded");
AddSignal (25, "SIGXFSZ", "XFSZ", false, true , true , "file size limit exceeded");
AddSignal (26, "SIGVTALRM", "VTALRM", false, true , true , "virtual time alarm");
- AddSignal (27, "SIGPROF", "PROF", false, true , true , "profiling time alarm");
+ AddSignal (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");
diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp
new file mode 100644
index 000000000000..5170e6d2accb
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp
@@ -0,0 +1,230 @@
+//===-- RegisterContextFreeBSD_powerpc.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_powerpc.h"
+#include "RegisterContextFreeBSD_powerpc.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// http://svnweb.freebsd.org/base/head/sys/powerpc/include/reg.h
+typedef struct _GPR64
+{
+ uint64_t r0;
+ 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 r28;
+ uint64_t r29;
+ uint64_t r30;
+ uint64_t r31;
+ uint64_t lr;
+ uint64_t cr;
+ uint64_t xer;
+ uint64_t ctr;
+ uint64_t pc;
+} GPR64;
+
+typedef struct _GPR32
+{
+ uint32_t r0;
+ 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 r28;
+ uint32_t r29;
+ uint32_t r30;
+ uint32_t r31;
+ uint32_t lr;
+ uint32_t cr;
+ uint32_t xer;
+ uint32_t ctr;
+ uint32_t pc;
+} GPR32;
+
+typedef struct _FPR
+{
+ uint64_t f0;
+ uint64_t f1;
+ uint64_t f2;
+ uint64_t f3;
+ uint64_t f4;
+ uint64_t f5;
+ uint64_t f6;
+ uint64_t f7;
+ uint64_t f8;
+ uint64_t f9;
+ uint64_t f10;
+ uint64_t f11;
+ uint64_t f12;
+ uint64_t f13;
+ uint64_t f14;
+ uint64_t f15;
+ uint64_t f16;
+ uint64_t f17;
+ uint64_t f18;
+ uint64_t f19;
+ uint64_t f20;
+ uint64_t f21;
+ uint64_t f22;
+ uint64_t f23;
+ uint64_t f24;
+ uint64_t f25;
+ uint64_t f26;
+ uint64_t f27;
+ uint64_t f28;
+ uint64_t f29;
+ uint64_t f30;
+ uint64_t f31;
+ uint64_t fpscr;
+} FPR;
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_powerpc to declare our g_register_infos_powerpc structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+#include "RegisterInfos_powerpc.h"
+#undef DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+
+RegisterContextFreeBSD_powerpc::RegisterContextFreeBSD_powerpc(const ArchSpec &target_arch) :
+ RegisterInfoInterface(target_arch)
+{
+}
+
+RegisterContextFreeBSD_powerpc::~RegisterContextFreeBSD_powerpc()
+{
+}
+
+size_t
+RegisterContextFreeBSD_powerpc::GetGPRSize() const
+{
+ // This is an 'abstract' base, so no GPR struct.
+ return 0;
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_powerpc::GetRegisterInfo() const
+{
+ //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc);
+ llvm_unreachable("Abstract class!");
+ return NULL;
+}
+
+uint32_t
+RegisterContextFreeBSD_powerpc::GetRegisterCount () const
+{
+ return 0;
+}
+
+RegisterContextFreeBSD_powerpc32::RegisterContextFreeBSD_powerpc32(const ArchSpec &target_arch) :
+ RegisterContextFreeBSD_powerpc(target_arch)
+{
+}
+
+RegisterContextFreeBSD_powerpc32::~RegisterContextFreeBSD_powerpc32()
+{
+}
+
+size_t
+RegisterContextFreeBSD_powerpc32::GetGPRSize() const
+{
+ return sizeof(GPR32);
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_powerpc32::GetRegisterInfo() const
+{
+ //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc);
+ return g_register_infos_powerpc32;
+}
+
+uint32_t
+RegisterContextFreeBSD_powerpc32::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_powerpc32) / sizeof (g_register_infos_powerpc32 [0]));
+}
+
+RegisterContextFreeBSD_powerpc64::RegisterContextFreeBSD_powerpc64(const ArchSpec &target_arch) :
+ RegisterContextFreeBSD_powerpc(target_arch)
+{
+}
+
+RegisterContextFreeBSD_powerpc64::~RegisterContextFreeBSD_powerpc64()
+{
+}
+
+size_t
+RegisterContextFreeBSD_powerpc64::GetGPRSize() const
+{
+ return sizeof(GPR64);
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_powerpc64::GetRegisterInfo() const
+{
+ //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc);
+ if (m_target_arch.GetMachine() == llvm::Triple::ppc)
+ return g_register_infos_powerpc64_32;
+ return g_register_infos_powerpc64;
+}
+
+uint32_t
+RegisterContextFreeBSD_powerpc64::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_powerpc64) / sizeof (g_register_infos_powerpc64 [0]));
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h
new file mode 100644
index 000000000000..b907fe99b5e0
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h
@@ -0,0 +1,66 @@
+//===-- RegisterContextFreeBSD_powerpc.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_powerpc_H_
+#define liblldb_RegisterContextFreeBSD_powerpc_H_
+
+#include "RegisterContextPOSIX.h"
+
+class RegisterContextFreeBSD_powerpc:
+ public lldb_private::RegisterInfoInterface
+{
+public:
+ RegisterContextFreeBSD_powerpc(const lldb_private::ArchSpec &target_arch);
+ virtual ~RegisterContextFreeBSD_powerpc();
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount() const override;
+};
+
+class RegisterContextFreeBSD_powerpc32:
+ public RegisterContextFreeBSD_powerpc
+{
+public:
+ RegisterContextFreeBSD_powerpc32(const lldb_private::ArchSpec &target_arch);
+ virtual ~RegisterContextFreeBSD_powerpc32();
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount() const override;
+};
+
+class RegisterContextFreeBSD_powerpc64:
+ public RegisterContextFreeBSD_powerpc
+{
+public:
+ RegisterContextFreeBSD_powerpc64(const lldb_private::ArchSpec &target_arch);
+ virtual ~RegisterContextFreeBSD_powerpc64();
+
+ 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/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
index b58e6bb607ed..f47d687702ec 100644
--- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -172,6 +172,21 @@ RegisterContextLLDB::InitializeZerothFrame()
m_sym_ctx_valid = true;
}
+ 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());
+ }
+ 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());
+ }
+ else
+ {
+ UnwindLogMsg ("with pc value of 0x%" PRIx64 ", no symbol/function name is known.", current_pc);
+ }
+
AddressRange addr_range;
m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range);
@@ -217,7 +232,6 @@ RegisterContextLLDB::InitializeZerothFrame()
m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
UnwindPlan::RowSP active_row;
- int cfa_offset = 0;
lldb::RegisterKind row_register_kind = eRegisterKindGeneric;
if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
{
@@ -239,18 +253,13 @@ RegisterContextLLDB::InitializeZerothFrame()
}
- addr_t cfa_regval = LLDB_INVALID_ADDRESS;
- if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+ if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa))
{
UnwindLogMsg ("could not read CFA register for this frame.");
m_frame_type = eNotAValidFrame;
return;
}
- cfa_offset = active_row->GetCFAOffset ();
- m_cfa = cfa_regval + cfa_offset;
-
- UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan",
(uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()),
(uint64_t) m_cfa,
@@ -294,20 +303,27 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (log)
{
- UnwindLogMsg ("pc = 0x%16.16" PRIx64, pc);
+ UnwindLogMsg ("pc = 0x%" PRIx64, pc);
addr_t reg_val;
if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
- UnwindLogMsg ("fp = 0x%16.16" PRIx64, reg_val);
+ UnwindLogMsg ("fp = 0x%" PRIx64, reg_val);
if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
- UnwindLogMsg ("sp = 0x%16.16" PRIx64, reg_val);
+ UnwindLogMsg ("sp = 0x%" PRIx64, reg_val);
}
- // A pc of 0x0 means it's the end of the stack crawl
- if (pc == 0)
+ // A pc of 0x0 means it's the end of the stack crawl unless we're above a trap handler function
+ bool above_trap_handler = false;
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsTrapHandlerFrame())
+ above_trap_handler = true;
+
+ if (pc == 0 || pc == 0x1)
{
- m_frame_type = eNotAValidFrame;
- UnwindLogMsg ("this frame has a pc of 0x0");
- return;
+ if (above_trap_handler == false)
+ {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("this frame has a pc of 0x0");
+ return;
+ }
}
ExecutionContext exe_ctx(m_thread.shared_from_this());
@@ -363,35 +379,31 @@ RegisterContextLLDB::InitializeNonZerothFrame()
m_all_registers_available = false;
m_current_offset = -1;
m_current_offset_backed_up_one = -1;
- addr_t cfa_regval = LLDB_INVALID_ADDRESS;
RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
if (row.get())
{
- uint32_t cfa_regnum = row->GetCFARegister();
- int cfa_offset = row->GetCFAOffset();
- if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval))
+ if (!ReadCFAValueForRow (row_register_kind, row, m_cfa))
{
UnwindLogMsg ("failed to get cfa value");
if (m_frame_type != eSkipFrame) // don't override eSkipFrame
{
- m_frame_type = eNormalFrame;
+ m_frame_type = eNotAValidFrame;
}
return;
}
- m_cfa = cfa_regval + cfa_offset;
// A couple of sanity checks..
- if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
+ if (m_cfa == LLDB_INVALID_ADDRESS || m_cfa == 0 || m_cfa == 1)
{
UnwindLogMsg ("could not find a valid cfa address");
m_frame_type = eNotAValidFrame;
return;
}
- // cfa_regval should point into the stack memory; if we can query memory region permissions,
+ // m_cfa should point into the stack memory; if we can query memory region permissions,
// see if the memory is allocated & readable.
- if (process->GetLoadAddressPermissions(cfa_regval, permissions)
+ if (process->GetLoadAddressPermissions(m_cfa, permissions)
&& (permissions & ePermissionsReadable) == 0)
{
m_frame_type = eNotAValidFrame;
@@ -406,6 +418,17 @@ RegisterContextLLDB::InitializeNonZerothFrame()
return;
}
+ if (CheckIfLoopingStack ())
+ {
+ TryFallbackUnwindPlan();
+ if (CheckIfLoopingStack ())
+ {
+ UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
UnwindLogMsg ("initialized frame cfa is 0x%" PRIx64, (uint64_t) m_cfa);
return;
}
@@ -431,6 +454,21 @@ RegisterContextLLDB::InitializeNonZerothFrame()
m_sym_ctx_valid = true;
}
+ 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());
+ }
+ 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());
+ }
+ else
+ {
+ UnwindLogMsg ("with pc value of 0x%" PRIx64 ", no symbol/function name is known.", pc);
+ }
+
AddressRange addr_range;
if (!m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range))
{
@@ -461,17 +499,22 @@ RegisterContextLLDB::InitializeNonZerothFrame()
// to the ABI plugin and consult that.
if (decr_pc_and_recompute_addr_range)
{
- Address temporary_pc(m_current_pc);
- temporary_pc.SetOffset(m_current_pc.GetOffset() - 1);
- m_sym_ctx.Clear(false);
+ 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());
+ Address temporary_pc;
+ temporary_pc.SetLoadAddress (pc - 1, &process->GetTarget());
+ m_sym_ctx.Clear (false);
m_sym_ctx_valid = false;
uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
- if (pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope)
+ ModuleSP temporary_module_sp = temporary_pc.GetModule();
+ if (temporary_module_sp &&
+ temporary_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope)
{
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());
}
// If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function.
@@ -479,13 +522,15 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (addr_range.GetBaseAddress().IsValid())
{
m_start_pc = addr_range.GetBaseAddress();
- m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+ m_current_offset = pc - m_start_pc.GetLoadAddress (&process->GetTarget());
m_current_offset_backed_up_one = m_current_offset;
if (decr_pc_and_recompute_addr_range && m_current_offset_backed_up_one > 0)
{
m_current_offset_backed_up_one--;
if (m_sym_ctx_valid)
- m_current_pc.SetOffset(m_current_pc.GetOffset() - 1);
+ {
+ m_current_pc.SetLoadAddress (pc - 1, &process->GetTarget());
+ }
}
}
else
@@ -512,7 +557,6 @@ RegisterContextLLDB::InitializeNonZerothFrame()
m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
UnwindPlan::RowSP active_row;
- int cfa_offset = 0;
RegisterKind row_register_kind = eRegisterKindGeneric;
// Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get
@@ -553,27 +597,33 @@ RegisterContextLLDB::InitializeNonZerothFrame()
return;
}
- addr_t cfa_regval = LLDB_INVALID_ADDRESS;
- if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+ if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa))
{
UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister());
m_frame_type = eNotAValidFrame;
return;
}
- cfa_offset = active_row->GetCFAOffset ();
- m_cfa = cfa_regval + cfa_offset;
+ UnwindLogMsg ("m_cfa = 0x%" PRIx64, m_cfa);
- UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
-
- // A couple of sanity checks..
- if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
+ if (CheckIfLoopingStack ())
{
- UnwindLogMsg ("could not find a valid cfa address");
- m_frame_type = eNotAValidFrame;
- return;
+ TryFallbackUnwindPlan();
+ if (CheckIfLoopingStack ())
+ {
+ UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
}
+ UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64,
+ (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa);
+}
+
+bool
+RegisterContextLLDB::CheckIfLoopingStack ()
+{
// If we have a bad stack setup, we can get the same CFA value multiple times -- or even
// more devious, we can actually oscillate between two CFA values. Detect that here and
// break out to avoid a possible infinite loop in lldb trying to unwind the stack.
@@ -581,29 +631,19 @@ RegisterContextLLDB::InitializeNonZerothFrame()
addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS;
if (GetNextFrame().get() && GetNextFrame()->GetCFA(next_frame_cfa))
{
- bool repeating_frames = false;
if (next_frame_cfa == m_cfa)
{
- repeating_frames = true;
- }
- else
- {
- if (GetNextFrame()->GetNextFrame() && GetNextFrame()->GetNextFrame()->GetCFA(next_next_frame_cfa)
- && next_next_frame_cfa == m_cfa)
- {
- repeating_frames = true;
- }
+ // We have a loop in the stack unwind
+ return true;
}
- if (repeating_frames && abi && abi->FunctionCallsChangeCFA())
+ if (GetNextFrame()->GetNextFrame().get() && GetNextFrame()->GetNextFrame()->GetCFA(next_next_frame_cfa)
+ && next_next_frame_cfa == m_cfa)
{
- UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping");
- m_frame_type = eNotAValidFrame;
- return;
+ // We have a loop in the stack unwind
+ return true;
}
}
-
- UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64,
- (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa);
+ return false;
}
@@ -715,13 +755,17 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
uint32_t permissions;
addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr());
if (current_pc_addr == 0
- || (process->GetLoadAddressPermissions (current_pc_addr, permissions)
+ || (process &&
+ process->GetLoadAddressPermissions (current_pc_addr, permissions)
&& (permissions & ePermissionsExecutable) == 0))
{
- unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
- abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
- m_frame_type = eNormalFrame;
- return unwind_plan_sp;
+ if (abi)
+ {
+ unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
}
}
@@ -764,10 +808,10 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// is properly encoded in the eh_frame section, so prefer that if available.
// On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of
// how to unwind out of sigtramp.
- if (m_frame_type == eTrapHandlerFrame)
+ if (m_frame_type == eTrapHandlerFrame && process)
{
m_fast_unwind_plan_sp.reset();
- unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (process->GetTarget(), m_current_offset_backed_up_one);
if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc) && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes)
{
return unwind_plan_sp;
@@ -782,7 +826,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// But there is not.
if (process && process->GetDynamicLoader() && process->GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo (m_sym_ctx))
{
- unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (process->GetTarget(), m_current_offset_backed_up_one);
if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
{
UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan because the DynamicLoader suggested we prefer it",
@@ -792,7 +836,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
}
// Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions
- if (behaves_like_zeroth_frame)
+ if (behaves_like_zeroth_frame && process)
{
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one);
if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
@@ -812,7 +856,10 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
}
// Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites
- unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ if (process)
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (process->GetTarget(), m_current_offset_backed_up_one);
+ }
int valid_offset = -1;
if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))
{
@@ -822,7 +869,10 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've
// struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.
- unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one);
+ if (process)
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one);
+ }
if (unwind_plan_sp && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
{
// We probably have an UnwindPlan created by inspecting assembly instructions, and we probably
@@ -908,6 +958,16 @@ RegisterContextLLDB::ReadRegisterValueFromRegisterLocation (lldb_private::Unwind
switch (regloc.type)
{
+ case UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+
+ if (!other_reg_info)
+ return false;
+
+ success = m_thread.GetRegisterContext()->ReadRegister (other_reg_info, value);
+ }
+ break;
case UnwindLLDB::RegisterLocation::eRegisterInRegister:
{
const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
@@ -962,6 +1022,12 @@ RegisterContextLLDB::WriteRegisterValueToRegisterLocation (lldb_private::UnwindL
switch (regloc.type)
{
+ case UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+ success = m_thread.GetRegisterContext()->WriteRegister (other_reg_info, value);
+ }
+ break;
case UnwindLLDB::RegisterLocation::eRegisterInRegister:
{
const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
@@ -1004,6 +1070,11 @@ RegisterContextLLDB::IsValid () const
return m_frame_type != eNotAValidFrame;
}
+// After the final stack frame in a stack walk we'll get one invalid (eNotAValidFrame) stack frame --
+// one past the end of the stack walk. But higher-level code will need to tell the differnece between
+// "the unwind plan below this frame failed" versus "we successfully completed the stack walk" so
+// this method helps to disambiguate that.
+
bool
RegisterContextLLDB::IsTrapHandlerFrame () const
{
@@ -1056,57 +1127,42 @@ RegisterContextLLDB::IsTrapHandlerSymbol (lldb_private::Process *process, const
enum UnwindLLDB::RegisterSearchResult
RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc)
{
+ RegisterNumber regnum (m_thread, eRegisterKindLLDB, lldb_regnum);
+
// Have we already found this register location?
if (!m_registers.empty())
{
std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation>::const_iterator iterator;
- iterator = m_registers.find (lldb_regnum);
+ iterator = m_registers.find (regnum.GetAsKind (eRegisterKindLLDB));
if (iterator != m_registers.end())
{
regloc = iterator->second;
- UnwindLogMsg ("supplying caller's saved reg %d's location, cached", lldb_regnum);
+ UnwindLogMsg ("supplying caller's saved %s (%d)'s location, cached",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
}
- uint32_t sp_regnum = LLDB_INVALID_REGNUM;
- uint32_t pc_regnum = LLDB_INVALID_REGNUM;
- m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, eRegisterKindLLDB, sp_regnum);
- m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, eRegisterKindLLDB, pc_regnum);
-
- // Are we looking for the CALLER's stack pointer? The stack pointer is defined to be the same as THIS frame's
- // CFA so just return the CFA value. This is true on x86-32/x86-64 at least.
- if (sp_regnum != LLDB_INVALID_REGNUM && sp_regnum == lldb_regnum)
- {
- // make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.inferred_value)
- assert (sizeof (addr_t) <= sizeof (uint64_t));
- regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
- regloc.location.inferred_value = m_cfa;
- m_registers[lldb_regnum] = regloc;
- UnwindLogMsg ("supplying caller's stack pointer (%d) value, computed from CFA", lldb_regnum);
- return UnwindLLDB::RegisterSearchResult::eRegisterFound;
- }
-
// Look through the available UnwindPlans for the register location.
UnwindPlan::Row::RegisterLocation unwindplan_regloc;
bool have_unwindplan_regloc = false;
- RegisterKind unwindplan_registerkind = (RegisterKind)-1;
+ RegisterKind unwindplan_registerkind = kNumRegisterKinds;
if (m_fast_unwind_plan_sp)
{
UnwindPlan::RowSP active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind ();
- uint32_t row_regnum;
- if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
+ if (regnum.GetAsKind (unwindplan_registerkind) == LLDB_INVALID_REGNUM)
{
- UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
- lldb_regnum, (int) unwindplan_registerkind);
+ UnwindLogMsg ("could not convert lldb regnum %s (%d) into %d RegisterKind reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), (int) unwindplan_registerkind);
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
- if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
+ if (active_row->GetRegisterInfo (regnum.GetAsKind (unwindplan_registerkind), unwindplan_regloc))
{
- UnwindLogMsg ("supplying caller's saved reg %d's location using FastUnwindPlan", lldb_regnum);
+ UnwindLogMsg ("supplying caller's saved %s (%d)'s location using FastUnwindPlan",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
have_unwindplan_regloc = true;
}
}
@@ -1119,37 +1175,49 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
if (m_full_unwind_plan_sp)
{
+ RegisterNumber pc_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+
UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind ();
- uint32_t row_regnum;
- bool row_register_rewritten_to_return_address_reg = false;
+
+ RegisterNumber return_address_reg;
// If we're fetching the saved pc and this UnwindPlan defines a ReturnAddress register (e.g. lr on arm),
// look for the return address register number in the UnwindPlan's row.
- if (lldb_regnum == pc_regnum && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM)
+ if (pc_regnum.IsValid()
+ && pc_regnum == regnum
+ && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM)
{
- row_regnum = m_full_unwind_plan_sp->GetReturnAddressRegister();
- row_register_rewritten_to_return_address_reg = true;
- UnwindLogMsg ("requested caller's saved PC but this UnwindPlan uses a RA reg; getting reg %d instead",
- row_regnum);
+
+ return_address_reg.init (m_thread, m_full_unwind_plan_sp->GetRegisterKind(), m_full_unwind_plan_sp->GetReturnAddressRegister());
+ regnum = return_address_reg;
+ UnwindLogMsg ("requested caller's saved PC but this UnwindPlan uses a RA reg; getting %s (%d) instead",
+ return_address_reg.GetName(), return_address_reg.GetAsKind (eRegisterKindLLDB));
}
else
{
- if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
+ if (regnum.GetAsKind (unwindplan_registerkind) == LLDB_INVALID_REGNUM)
{
if (unwindplan_registerkind == eRegisterKindGeneric)
- UnwindLogMsg ("could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme", lldb_regnum);
+ {
+ UnwindLogMsg ("could not convert lldb regnum %s (%d) into eRegisterKindGeneric reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ }
else
- UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
- lldb_regnum, (int) unwindplan_registerkind);
+ {
+ UnwindLogMsg ("could not convert lldb regnum %s (%d) into %d RegisterKind reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), (int) unwindplan_registerkind);
+ }
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
}
- if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
+ if (regnum.IsValid()
+ && active_row->GetRegisterInfo (regnum.GetAsKind (unwindplan_registerkind), unwindplan_regloc))
{
have_unwindplan_regloc = true;
- UnwindLogMsg ("supplying caller's saved reg %d's location using %s UnwindPlan", lldb_regnum,
+ UnwindLogMsg ("supplying caller's saved %s (%d)'s location using %s UnwindPlan",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
m_full_unwind_plan_sp->GetSourceName().GetCString());
}
@@ -1158,19 +1226,19 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
// Handle this specially.
if (have_unwindplan_regloc == false
- && row_register_rewritten_to_return_address_reg == true
- && IsFrameZero()
- && row_regnum != LLDB_INVALID_REGNUM)
+ && return_address_reg.IsValid()
+ && IsFrameZero())
{
- uint32_t ra_regnum_in_lldb_reg_numbering;
- if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, row_regnum, eRegisterKindLLDB, ra_regnum_in_lldb_reg_numbering))
+ if (return_address_reg.GetAsKind (eRegisterKindLLDB) != LLDB_INVALID_REGNUM)
{
lldb_private::UnwindLLDB::RegisterLocation new_regloc;
- new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
- new_regloc.location.register_number = ra_regnum_in_lldb_reg_numbering;
- m_registers[lldb_regnum] = new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext;
+ new_regloc.location.register_number = return_address_reg.GetAsKind (eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = new_regloc;
regloc = new_regloc;
- UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0, saved in %d", lldb_regnum, ra_regnum_in_lldb_reg_numbering);
+ UnwindLogMsg ("supplying caller's register %s (%d) from the live RegisterContext at frame 0, saved in %d",
+ return_address_reg.GetName(), return_address_reg.GetAsKind (eRegisterKindLLDB),
+ return_address_reg.GetAsKind (eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
}
@@ -1187,13 +1255,12 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
// when we're at a call site location.
// arch_default_ra_regnum is the return address register # in the Full UnwindPlan register numbering
- uint32_t arch_default_ra_regnum = LLDB_INVALID_REGNUM;
- if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, unwindplan_registerkind, arch_default_ra_regnum)
- && arch_default_ra_regnum != LLDB_INVALID_REGNUM
- && pc_regnum != LLDB_INVALID_REGNUM
- && pc_regnum == lldb_regnum
+ RegisterNumber arch_default_ra_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+
+ if (arch_default_ra_regnum.GetAsKind (unwindplan_registerkind) != LLDB_INVALID_REGNUM
+ && pc_regnum == regnum
&& unwindplan_regloc.IsInOtherRegister()
- && unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum
+ && unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum.GetAsKind (unwindplan_registerkind)
&& m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes
&& !m_all_registers_available)
{
@@ -1201,15 +1268,32 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
m_full_unwind_plan_sp->GetSourceName().GetCString());
// Throw away the full unwindplan; install the arch default unwindplan
- if (TryFallbackUnwindPlan())
+ if (ForceSwitchToFallbackUnwindPlan())
{
- // Now re-fetch the pc value we're searching for
- uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM;
+ // Update for the possibly new unwind plan
+ unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind ();
UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
- if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg)
- && arch_default_pc_reg != LLDB_INVALID_REGNUM
- && active_row
- && active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc))
+
+ // Sanity check: Verify that we can fetch a pc value and CFA value with this unwind plan
+
+ RegisterNumber arch_default_pc_reg (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ bool can_fetch_pc_value = false;
+ bool can_fetch_cfa = false;
+ addr_t cfa_value;
+ if (active_row)
+ {
+ if (arch_default_pc_reg.GetAsKind (unwindplan_registerkind) != LLDB_INVALID_REGNUM
+ && active_row->GetRegisterInfo (arch_default_pc_reg.GetAsKind (unwindplan_registerkind), unwindplan_regloc))
+ {
+ can_fetch_pc_value = true;
+ }
+ if (ReadCFAValueForRow (unwindplan_registerkind, active_row, cfa_value))
+ {
+ can_fetch_cfa = true;
+ }
+ }
+
+ if (can_fetch_pc_value && can_fetch_cfa)
{
have_unwindplan_regloc = true;
}
@@ -1218,10 +1302,35 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
have_unwindplan_regloc = false;
}
}
+ else
+ {
+ // We were unable to fall back to another unwind plan
+ have_unwindplan_regloc = false;
+ }
}
}
}
+ if (have_unwindplan_regloc == false)
+ {
+ // Did the UnwindPlan fail to give us the caller's stack pointer?
+ // The stack pointer is defined to be the same as THIS frame's CFA, so return the CFA value as
+ // the caller's stack pointer. This is true on x86-32/x86-64 at least.
+
+ RegisterNumber sp_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ if (sp_regnum.GetAsKind (eRegisterKindLLDB) != LLDB_INVALID_REGNUM
+ && sp_regnum.GetAsKind (eRegisterKindLLDB) == regnum.GetAsKind (eRegisterKindLLDB))
+ {
+ // make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.inferred_value)
+ assert (sizeof (addr_t) <= sizeof (uint64_t));
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_cfa;
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's stack pointer %s (%d) value, computed from CFA",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
ExecutionContext exe_ctx(m_thread.shared_from_this());
Process *process = exe_ctx.GetProcessPtr();
@@ -1232,11 +1341,11 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
ABI *abi = process ? process->GetABI().get() : NULL;
if (abi)
{
- const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(regnum.GetAsKind (eRegisterKindLLDB));
if (reg_info && abi->RegisterIsVolatile (reg_info))
{
- UnwindLogMsg ("did not supply reg location for %d (%s) because it is volatile",
- lldb_regnum, reg_info->name ? reg_info->name : "??");
+ UnwindLogMsg ("did not supply reg location for %s (%d) because it is volatile",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
}
}
@@ -1245,15 +1354,27 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
{
// This is frame 0 - we should return the actual live register context value
lldb_private::UnwindLLDB::RegisterLocation new_regloc;
- new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
- new_regloc.location.register_number = lldb_regnum;
- m_registers[lldb_regnum] = new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext;
+ new_regloc.location.register_number = regnum.GetAsKind (eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = new_regloc;
regloc = new_regloc;
- UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0", lldb_regnum);
+ UnwindLogMsg ("supplying caller's register %s (%d) from the live RegisterContext at frame 0",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
else
- UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ {
+ std::string unwindplan_name ("");
+ if (m_full_unwind_plan_sp)
+ {
+ unwindplan_name += "via '";
+ unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString();
+ unwindplan_name += "'";
+ }
+ UnwindLogMsg ("no save location for %s (%d) %s",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
+ unwindplan_name.c_str());
+ }
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
@@ -1262,8 +1383,9 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
{
lldb_private::UnwindLLDB::RegisterLocation new_regloc;
new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved;
- m_registers[lldb_regnum] = new_regloc;
- UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = new_regloc;
+ UnwindLogMsg ("save location for %s (%d) is unspecified, continue searching",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
@@ -1271,7 +1393,8 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
{
if (IsFrameZero ())
{
- UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ UnwindLogMsg ("could not supply caller's %s (%d) location, IsSame",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
else
@@ -1285,8 +1408,10 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
int offset = unwindplan_regloc.GetOffset();
regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
regloc.location.inferred_value = m_cfa + offset;
- m_registers[lldb_regnum] = regloc;
- UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset %d", lldb_regnum, offset);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d), value is CFA plus offset %d [value is 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
+ offset, regloc.location.inferred_value);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
@@ -1295,24 +1420,29 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
int offset = unwindplan_regloc.GetOffset();
regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
regloc.location.target_memory_location = m_cfa + offset;
- m_registers[lldb_regnum] = regloc;
- UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset %d", lldb_regnum, offset);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d) from the stack, saved at CFA plus offset %d [saved at 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
+ offset, regloc.location.target_memory_location);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
if (unwindplan_regloc.IsInOtherRegister())
{
uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber();
- uint32_t row_regnum_in_lldb;
- if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, unwindplan_regnum, eRegisterKindLLDB, row_regnum_in_lldb))
+ RegisterNumber row_regnum (m_thread, unwindplan_registerkind, unwindplan_regnum);
+ if (row_regnum.GetAsKind (eRegisterKindLLDB) == LLDB_INVALID_REGNUM)
{
- UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ UnwindLogMsg ("could not supply caller's %s (%d) location - was saved in another reg but couldn't convert that regnum",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
- regloc.location.register_number = row_regnum_in_lldb;
- m_registers[lldb_regnum] = regloc;
- UnwindLogMsg ("supplying caller's register %d, saved in register %d", lldb_regnum, row_regnum_in_lldb);
+ regloc.location.register_number = row_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),
+ row_regnum.GetName(), row_regnum.GetAsKind (eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
@@ -1334,75 +1464,277 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
{
regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
regloc.location.inferred_value = val;
- m_registers[lldb_regnum] = regloc;
- UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsDWARFExpression)", lldb_regnum);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d) via DWARF expression (IsDWARFExpression)",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
else
{
regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
regloc.location.target_memory_location = val;
- m_registers[lldb_regnum] = regloc;
- UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsAtDWARFExpression)", lldb_regnum);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d) via DWARF expression (IsAtDWARFExpression)",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
}
- UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for reg %d but failed", lldb_regnum);
+ UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for %s (%d) but failed",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
- UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ UnwindLogMsg ("no save location for %s (%d) in this stack frame",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
// FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are unsupported.
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
-// If the Full unwindplan has been determined to be incorrect, this method will
-// replace it with the architecture's default unwindplan, if one is defined.
-// It will also find the FuncUnwinders object for this function and replace the
-// Full unwind method for the function there so we don't use the errant Full unwindplan
-// again in the future of this debug session.
-// We're most likely doing this because the Full unwindplan was generated by assembly
-// instruction profiling and the profiler got something wrong.
+// TryFallbackUnwindPlan() -- this method is a little tricky.
+//
+// When this is called, the frame above -- the caller frame, the "previous" frame --
+// is invalid or bad.
+//
+// Instead of stopping the stack walk here, we'll try a different UnwindPlan and see
+// if we can get a valid frame above us.
+//
+// This most often happens when an unwind plan based on assembly instruction inspection
+// is not correct -- mostly with hand-written assembly functions or functions where the
+// stack frame is set up "out of band", e.g. the kernel saved the register context and
+// then called an asynchronous trap handler like _sigtramp.
+//
+// Often in these cases, if we just do a dumb stack walk we'll get past this tricky
+// frame and our usual techniques can continue to be used.
bool
RegisterContextLLDB::TryFallbackUnwindPlan ()
{
- UnwindPlan::Row::RegisterLocation unwindplan_regloc;
- if (m_fallback_unwind_plan_sp.get() == NULL)
+ if (m_fallback_unwind_plan_sp.get() == nullptr)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == nullptr)
return false;
+ if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get()
+ || m_full_unwind_plan_sp->GetSourceName() == m_fallback_unwind_plan_sp->GetSourceName())
+ {
+ return false;
+ }
+
+ // If a compiler generated unwind plan failed, trying the arch default unwindplan
+ // isn't going to do any better.
+ if (m_full_unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes)
+ return false;
+
+
+ // Get the caller's pc value and our own CFA value.
+ // Swap in the fallback unwind plan, re-fetch the caller's pc value and CFA value.
+ // If they're the same, then the fallback unwind plan provides no benefit.
+
+ RegisterNumber pc_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+
+ addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS;
+ addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS;
+ addr_t old_this_frame_cfa_value = m_cfa;
+ UnwindLLDB::RegisterLocation regloc;
+ if (SavedLocationForRegister (pc_regnum.GetAsKind (eRegisterKindLLDB), regloc) == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(pc_regnum.GetAsKind (eRegisterKindLLDB));
+ if (reg_info)
+ {
+ RegisterValue reg_value;
+ if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value))
+ {
+ old_caller_pc_value = reg_value.GetAsUInt64();
+ }
+ }
+ }
+
+ // This is a tricky wrinkle! If SavedLocationForRegister() detects a really impossible
+ // register location for the full unwind plan, it may call ForceSwitchToFallbackUnwindPlan()
+ // which in turn replaces the full unwindplan with the fallback... in short, we're done,
+ // we're using the fallback UnwindPlan.
+ // We checked if m_fallback_unwind_plan_sp was nullptr at the top -- the only way it
+ // became nullptr since then is via SavedLocationForRegister().
+ if (m_fallback_unwind_plan_sp.get() == nullptr)
+ return true;
+
+
+ // Switch the full UnwindPlan to be the fallback UnwindPlan. If we decide this isn't
+ // working, we need to restore.
+ // We'll also need to save & restore the value of the m_cfa ivar. Save is down below a bit in 'old_cfa'.
UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
+ addr_t old_cfa = m_cfa;
+
+ m_registers.clear();
+
+ m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
+
UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM)
{
- FuncUnwindersSP func_unwinders_sp;
- if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule())
+ addr_t new_cfa;
+ if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa)
+ || new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS)
+ {
+ UnwindLogMsg ("failed to get cfa with fallback unwindplan");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ m_cfa = old_cfa;
+ return false;
+ }
+ m_cfa = new_cfa;
+
+ if (SavedLocationForRegister (pc_regnum.GetAsKind (eRegisterKindLLDB), regloc) == UnwindLLDB::RegisterSearchResult::eRegisterFound)
{
- func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
- if (func_unwinders_sp)
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(pc_regnum.GetAsKind (eRegisterKindLLDB));
+ if (reg_info)
{
- func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread);
+ RegisterValue reg_value;
+ if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value))
+ {
+ new_caller_pc_value = reg_value.GetAsUInt64();
+ }
}
}
- m_registers.clear();
- m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
- addr_t cfa_regval = LLDB_INVALID_ADDRESS;
- if (ReadGPRValue (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval))
+
+
+ if (new_caller_pc_value == LLDB_INVALID_ADDRESS)
{
- m_cfa = cfa_regval + active_row->GetCFAOffset ();
+ UnwindLogMsg ("failed to get a pc value for the caller frame with the fallback unwind plan");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ m_cfa = old_cfa;
+ return false;
+ }
+
+ if (old_caller_pc_value != LLDB_INVALID_ADDRESS)
+ {
+ if (old_caller_pc_value == new_caller_pc_value && new_cfa == old_this_frame_cfa_value)
+ {
+ UnwindLogMsg ("fallback unwind plan got the same values for this frame CFA and caller frame pc, not using");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ m_cfa = old_cfa;
+ return false;
+ }
}
- UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.",
- original_full_unwind_plan_sp->GetSourceName().GetCString(), m_fallback_unwind_plan_sp->GetSourceName().GetCString());
+ UnwindLogMsg ("trying to unwind from this function with the UnwindPlan '%s' because UnwindPlan '%s' failed.",
+ m_fallback_unwind_plan_sp->GetSourceName().GetCString(),
+ original_full_unwind_plan_sp->GetSourceName().GetCString());
+
+ // We've copied the fallback unwind plan into the full - now clear the fallback.
m_fallback_unwind_plan_sp.reset();
}
return true;
}
+bool
+RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan ()
+{
+ if (m_fallback_unwind_plan_sp.get() == NULL)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == NULL)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get()
+ || m_full_unwind_plan_sp->GetSourceName() == m_fallback_unwind_plan_sp->GetSourceName())
+ {
+ return false;
+ }
+
+ UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+
+ if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM)
+ {
+ addr_t new_cfa;
+ if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa)
+ || new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS)
+ {
+ UnwindLogMsg ("failed to get cfa with fallback unwindplan");
+ m_fallback_unwind_plan_sp.reset();
+ return false;
+ }
+
+ m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
+ m_fallback_unwind_plan_sp.reset();
+
+ m_registers.clear();
+
+ m_cfa = new_cfa;
+
+ UnwindLogMsg ("switched unconditionally to the fallback unwindplan %s", m_full_unwind_plan_sp->GetSourceName().GetCString());
+ return true;
+ }
+ return false;
+}
+
+bool
+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))
+ {
+ if (row->GetCFAType() == UnwindPlan::Row::CFAIsRegisterDereferenced)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (cfa_reg.GetAsKind (eRegisterKindLLDB));
+ RegisterValue reg_value;
+ if (reg_info)
+ {
+ 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
+ {
+ if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || cfa_reg_contents == 1)
+ {
+ 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->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;
+ }
+ }
+ return false;
+}
+
// Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that
// this frame called. e.g.
//
@@ -1471,6 +1803,12 @@ RegisterContextLLDB::ReadGPRValue (lldb::RegisterKind register_kind, uint32_t re
return false;
}
+bool
+RegisterContextLLDB::ReadGPRValue (const RegisterNumber &regnum, addr_t &value)
+{
+ return ReadGPRValue (regnum.GetRegisterKind(), regnum.GetRegisterNumber(), value);
+}
+
// Find the value of a register in THIS frame
bool
@@ -1593,6 +1931,10 @@ RegisterContextLLDB::ReadPC (addr_t& pc)
if (!IsValid())
return false;
+ bool above_trap_handler = false;
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsTrapHandlerFrame())
+ above_trap_handler = true;
+
if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
{
// A pc value of 0 or 1 is impossible in the middle of the stack -- it indicates the end of a stack walk.
@@ -1601,6 +1943,7 @@ RegisterContextLLDB::ReadPC (addr_t& pc)
// find the bug.
if (m_all_registers_available == false
+ && above_trap_handler == false
&& (pc == 0 || pc == 1))
{
return false;
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h
index d6ecfeb68caa..5f94a977448d 100644
--- a/source/Plugins/Process/Utility/RegisterContextLLDB.h
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -16,6 +16,7 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/RegisterNumber.h"
#include "UnwindLLDB.h"
namespace lldb_private {
@@ -98,6 +99,12 @@ private:
// UnwindLLDB needs to pass around references to RegisterLocations
friend class UnwindLLDB;
+
+ // Returns true if we have an unwind loop -- the same stack frame unwinding
+ // multiple times.
+ bool
+ CheckIfLoopingStack ();
+
// Indicates whether this frame is frame zero -- the currently
// executing frame -- or not.
bool
@@ -175,11 +182,30 @@ private:
bool
TryFallbackUnwindPlan ();
+ //------------------------------------------------------------------
+ /// Switch to the fallback unwind plan unconditionally without any safety
+ /// checks that it is providing better results than the normal unwind plan.
+ ///
+ /// The only time it is valid to call this method is if the full unwindplan is
+ /// found to be fundamentally incorrect/impossible.
+ ///
+ /// Returns true if it was able to install the fallback unwind plan.
+ //------------------------------------------------------------------
+ bool
+ ForceSwitchToFallbackUnwindPlan ();
+
// Get the contents of a general purpose (address-size) register for this frame
// (usually retrieved from the next frame)
bool
ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, lldb::addr_t &value);
+ bool
+ ReadGPRValue (const RegisterNumber &reg_num, lldb::addr_t &value);
+
+ // Get the CFA register for a given frame.
+ bool
+ ReadCFAValueForRow (lldb::RegisterKind register_kind, const UnwindPlan::RowSP &row, lldb::addr_t &value);
+
lldb::UnwindPlanSP
GetFastUnwindPlanForFrame ();
diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
index e246e715de86..a2ab67438b75 100644
--- a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
@@ -149,7 +149,8 @@ RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info,
// TOOD: need a better way to detect when "long double" types are
// the same bytes size as "double"
-#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) && !defined(_MSC_VER) && !defined(__mips__)
+#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) && !defined(_MSC_VER) && \
+ !defined(__mips__) && !defined(__powerpc__) && !defined(__ANDROID_NDK__)
case sizeof (long double):
if (sizeof (long double) == sizeof(uint32_t))
{
diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
new file mode 100644
index 000000000000..a9477d583517
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
@@ -0,0 +1,273 @@
+//===-- RegisterContextPOSIX_powerpc.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_powerpc.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+static const
+uint32_t g_gpr_regnums[] =
+{
+ gpr_r0_powerpc,
+ gpr_r1_powerpc,
+ gpr_r2_powerpc,
+ gpr_r3_powerpc,
+ gpr_r4_powerpc,
+ gpr_r5_powerpc,
+ gpr_r6_powerpc,
+ gpr_r7_powerpc,
+ gpr_r8_powerpc,
+ gpr_r9_powerpc,
+ gpr_r10_powerpc,
+ gpr_r11_powerpc,
+ gpr_r12_powerpc,
+ gpr_r13_powerpc,
+ gpr_r14_powerpc,
+ gpr_r15_powerpc,
+ gpr_r16_powerpc,
+ gpr_r17_powerpc,
+ gpr_r18_powerpc,
+ gpr_r19_powerpc,
+ gpr_r20_powerpc,
+ gpr_r21_powerpc,
+ gpr_r22_powerpc,
+ gpr_r23_powerpc,
+ gpr_r24_powerpc,
+ gpr_r25_powerpc,
+ gpr_r26_powerpc,
+ gpr_r27_powerpc,
+ gpr_r28_powerpc,
+ gpr_r29_powerpc,
+ gpr_r30_powerpc,
+ gpr_r31_powerpc,
+ gpr_lr_powerpc,
+ gpr_cr_powerpc,
+ gpr_xer_powerpc,
+ gpr_ctr_powerpc,
+ gpr_pc_powerpc,
+};
+
+static const
+uint32_t g_fpr_regnums[] =
+{
+ fpr_f0_powerpc,
+ fpr_f1_powerpc,
+ fpr_f2_powerpc,
+ fpr_f3_powerpc,
+ fpr_f4_powerpc,
+ fpr_f5_powerpc,
+ fpr_f6_powerpc,
+ fpr_f7_powerpc,
+ fpr_f8_powerpc,
+ fpr_f9_powerpc,
+ fpr_f10_powerpc,
+ fpr_f11_powerpc,
+ fpr_f12_powerpc,
+ fpr_f13_powerpc,
+ fpr_f14_powerpc,
+ fpr_f15_powerpc,
+ fpr_f16_powerpc,
+ fpr_f17_powerpc,
+ fpr_f18_powerpc,
+ fpr_f19_powerpc,
+ fpr_f20_powerpc,
+ fpr_f21_powerpc,
+ fpr_f22_powerpc,
+ fpr_f23_powerpc,
+ fpr_f24_powerpc,
+ fpr_f25_powerpc,
+ fpr_f26_powerpc,
+ fpr_f27_powerpc,
+ fpr_f28_powerpc,
+ fpr_f29_powerpc,
+ fpr_f30_powerpc,
+ fpr_f31_powerpc,
+ fpr_fpscr_powerpc,
+};
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_register_sets = 2
+};
+
+static const RegisterSet
+g_reg_sets_powerpc[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_powerpc, g_gpr_regnums },
+ { "Floating Point Registers", "fpr", k_num_fpr_registers_powerpc, g_fpr_regnums },
+};
+
+bool RegisterContextPOSIX_powerpc::IsGPR(unsigned reg)
+{
+ return reg <= k_num_gpr_registers_powerpc; // GPR's come first.
+}
+
+bool
+RegisterContextPOSIX_powerpc::IsFPR(unsigned reg)
+{
+ // XXX
+ return (reg >= k_first_fpr) && (reg <= k_last_fpr);
+}
+
+RegisterContextPOSIX_powerpc::RegisterContextPOSIX_powerpc(Thread &thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info)
+ : RegisterContext(thread, concrete_frame_idx)
+{
+ m_register_info_ap.reset(register_info);
+
+ // elf-core yet to support ReadFPR()
+ ProcessSP base = CalculateProcess();
+ if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return;
+}
+
+RegisterContextPOSIX_powerpc::~RegisterContextPOSIX_powerpc()
+{
+}
+
+void
+RegisterContextPOSIX_powerpc::Invalidate()
+{
+}
+
+void
+RegisterContextPOSIX_powerpc::InvalidateAllRegisters()
+{
+}
+
+unsigned
+RegisterContextPOSIX_powerpc::GetRegisterOffset(unsigned reg)
+{
+ assert(reg < k_num_registers_powerpc && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned
+RegisterContextPOSIX_powerpc::GetRegisterSize(unsigned reg)
+{
+ assert(reg < k_num_registers_powerpc && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t
+RegisterContextPOSIX_powerpc::GetRegisterCount()
+{
+ size_t num_registers = k_num_registers_powerpc;
+ return num_registers;
+}
+
+size_t
+RegisterContextPOSIX_powerpc::GetGPRSize()
+{
+ return m_register_info_ap->GetGPRSize();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_powerpc::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 RegisterInfo *
+RegisterContextPOSIX_powerpc::GetRegisterInfoAtIndex(size_t reg)
+{
+ if (reg < k_num_registers_powerpc)
+ return &GetRegisterInfo()[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContextPOSIX_powerpc::GetRegisterSetCount()
+{
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set)
+ {
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+ }
+
+ return sets;
+}
+
+const RegisterSet *
+RegisterContextPOSIX_powerpc::GetRegisterSet(size_t set)
+{
+ if (IsRegisterSetAvailable(set))
+ return &g_reg_sets_powerpc[set];
+ else
+ return NULL;
+}
+
+const char *
+RegisterContextPOSIX_powerpc::GetRegisterName(unsigned reg)
+{
+ assert(reg < k_num_registers_powerpc && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+lldb::ByteOrder
+RegisterContextPOSIX_powerpc::GetByteOrder()
+{
+ // Get the target process whose privileged thread was used for the register read.
+ lldb::ByteOrder byte_order = eByteOrderInvalid;
+ Process *process = CalculateProcess().get();
+
+ if (process)
+ byte_order = process->GetByteOrder();
+ return byte_order;
+}
+
+bool
+RegisterContextPOSIX_powerpc::IsRegisterSetAvailable(size_t set_index)
+{
+ size_t num_sets = k_num_register_sets;
+
+ return (set_index < num_sets);
+}
+
+// Used when parsing DWARF and EH frame information and any other
+// object file sections that contain register numbers in them.
+uint32_t
+RegisterContextPOSIX_powerpc::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num)
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert (kind < kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
new file mode 100644
index 000000000000..3194c3968c98
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
@@ -0,0 +1,173 @@
+//===-- RegisterContextPOSIX_powerpc.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_powerpc_H_
+#define liblldb_RegisterContextPOSIX_powerpc_H_
+
+#include "lldb/Core/Log.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterContext_powerpc.h"
+
+class ProcessMonitor;
+
+// ---------------------------------------------------------------------------
+// Internal codes for all powerpc registers.
+// ---------------------------------------------------------------------------
+enum
+{
+ k_first_gpr_powerpc,
+ gpr_r0_powerpc = k_first_gpr_powerpc,
+ gpr_r1_powerpc,
+ gpr_r2_powerpc,
+ gpr_r3_powerpc,
+ gpr_r4_powerpc,
+ gpr_r5_powerpc,
+ gpr_r6_powerpc,
+ gpr_r7_powerpc,
+ gpr_r8_powerpc,
+ gpr_r9_powerpc,
+ gpr_r10_powerpc,
+ gpr_r11_powerpc,
+ gpr_r12_powerpc,
+ gpr_r13_powerpc,
+ gpr_r14_powerpc,
+ gpr_r15_powerpc,
+ gpr_r16_powerpc,
+ gpr_r17_powerpc,
+ gpr_r18_powerpc,
+ gpr_r19_powerpc,
+ gpr_r20_powerpc,
+ gpr_r21_powerpc,
+ gpr_r22_powerpc,
+ gpr_r23_powerpc,
+ gpr_r24_powerpc,
+ gpr_r25_powerpc,
+ gpr_r26_powerpc,
+ gpr_r27_powerpc,
+ gpr_r28_powerpc,
+ gpr_r29_powerpc,
+ gpr_r30_powerpc,
+ gpr_r31_powerpc,
+ gpr_lr_powerpc,
+ gpr_cr_powerpc,
+ gpr_xer_powerpc,
+ gpr_ctr_powerpc,
+ gpr_pc_powerpc,
+ k_last_gpr_powerpc = gpr_pc_powerpc,
+
+ k_first_fpr,
+ fpr_f0_powerpc = k_first_fpr,
+ fpr_f1_powerpc,
+ fpr_f2_powerpc,
+ fpr_f3_powerpc,
+ fpr_f4_powerpc,
+ fpr_f5_powerpc,
+ fpr_f6_powerpc,
+ fpr_f7_powerpc,
+ fpr_f8_powerpc,
+ fpr_f9_powerpc,
+ fpr_f10_powerpc,
+ fpr_f11_powerpc,
+ fpr_f12_powerpc,
+ fpr_f13_powerpc,
+ fpr_f14_powerpc,
+ fpr_f15_powerpc,
+ fpr_f16_powerpc,
+ fpr_f17_powerpc,
+ fpr_f18_powerpc,
+ fpr_f19_powerpc,
+ fpr_f20_powerpc,
+ fpr_f21_powerpc,
+ fpr_f22_powerpc,
+ fpr_f23_powerpc,
+ fpr_f24_powerpc,
+ fpr_f25_powerpc,
+ fpr_f26_powerpc,
+ fpr_f27_powerpc,
+ fpr_f28_powerpc,
+ fpr_f29_powerpc,
+ fpr_f30_powerpc,
+ fpr_f31_powerpc,
+ fpr_fpscr_powerpc,
+ k_last_fpr = fpr_fpscr_powerpc,
+
+ k_num_registers_powerpc,
+ k_num_gpr_registers_powerpc = k_last_gpr_powerpc - k_first_gpr_powerpc + 1,
+ k_num_fpr_registers_powerpc = k_last_fpr - k_first_fpr + 1,
+};
+
+class RegisterContextPOSIX_powerpc
+ : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextPOSIX_powerpc (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ ~RegisterContextPOSIX_powerpc();
+
+ 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:
+ uint64_t m_gpr_powerpc[k_num_gpr_registers_powerpc]; // general purpose registers.
+ 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_powerpc_H_
diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
index 2925a33a1690..77b6385da8bd 100644
--- a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
@@ -30,96 +30,96 @@ using namespace lldb;
const uint32_t
g_gpr_regnums_i386[] =
{
- gpr_eax_i386,
- gpr_ebx_i386,
- gpr_ecx_i386,
- gpr_edx_i386,
- gpr_edi_i386,
- gpr_esi_i386,
- gpr_ebp_i386,
- gpr_esp_i386,
- gpr_eip_i386,
- gpr_eflags_i386,
- gpr_cs_i386,
- gpr_fs_i386,
- gpr_gs_i386,
- gpr_ss_i386,
- gpr_ds_i386,
- gpr_es_i386,
- gpr_ax_i386,
- gpr_bx_i386,
- gpr_cx_i386,
- gpr_dx_i386,
- gpr_di_i386,
- gpr_si_i386,
- gpr_bp_i386,
- gpr_sp_i386,
- gpr_ah_i386,
- gpr_bh_i386,
- gpr_ch_i386,
- gpr_dh_i386,
- gpr_al_i386,
- gpr_bl_i386,
- gpr_cl_i386,
- gpr_dl_i386,
+ lldb_eax_i386,
+ lldb_ebx_i386,
+ lldb_ecx_i386,
+ lldb_edx_i386,
+ lldb_edi_i386,
+ lldb_esi_i386,
+ lldb_ebp_i386,
+ lldb_esp_i386,
+ lldb_eip_i386,
+ lldb_eflags_i386,
+ lldb_cs_i386,
+ lldb_fs_i386,
+ lldb_gs_i386,
+ lldb_ss_i386,
+ lldb_ds_i386,
+ lldb_es_i386,
+ lldb_ax_i386,
+ lldb_bx_i386,
+ lldb_cx_i386,
+ lldb_dx_i386,
+ lldb_di_i386,
+ lldb_si_i386,
+ lldb_bp_i386,
+ lldb_sp_i386,
+ lldb_ah_i386,
+ lldb_bh_i386,
+ lldb_ch_i386,
+ lldb_dh_i386,
+ lldb_al_i386,
+ lldb_bl_i386,
+ lldb_cl_i386,
+ lldb_dl_i386,
LLDB_INVALID_REGNUM, // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - 1 == k_num_gpr_registers_i386,
"g_gpr_regnums_i386 has wrong number of register infos");
const uint32_t
-g_fpu_regnums_i386[] =
-{
- fpu_fctrl_i386,
- fpu_fstat_i386,
- fpu_ftag_i386,
- fpu_fop_i386,
- fpu_fiseg_i386,
- fpu_fioff_i386,
- fpu_foseg_i386,
- fpu_fooff_i386,
- fpu_mxcsr_i386,
- fpu_mxcsrmask_i386,
- fpu_st0_i386,
- fpu_st1_i386,
- fpu_st2_i386,
- fpu_st3_i386,
- fpu_st4_i386,
- fpu_st5_i386,
- fpu_st6_i386,
- fpu_st7_i386,
- fpu_mm0_i386,
- fpu_mm1_i386,
- fpu_mm2_i386,
- fpu_mm3_i386,
- fpu_mm4_i386,
- fpu_mm5_i386,
- fpu_mm6_i386,
- fpu_mm7_i386,
- fpu_xmm0_i386,
- fpu_xmm1_i386,
- fpu_xmm2_i386,
- fpu_xmm3_i386,
- fpu_xmm4_i386,
- fpu_xmm5_i386,
- fpu_xmm6_i386,
- fpu_xmm7_i386,
+g_lldb_regnums_i386[] =
+{
+ lldb_fctrl_i386,
+ lldb_fstat_i386,
+ lldb_ftag_i386,
+ lldb_fop_i386,
+ lldb_fiseg_i386,
+ lldb_fioff_i386,
+ lldb_foseg_i386,
+ lldb_fooff_i386,
+ lldb_mxcsr_i386,
+ lldb_mxcsrmask_i386,
+ lldb_st0_i386,
+ lldb_st1_i386,
+ lldb_st2_i386,
+ lldb_st3_i386,
+ lldb_st4_i386,
+ lldb_st5_i386,
+ lldb_st6_i386,
+ lldb_st7_i386,
+ lldb_mm0_i386,
+ lldb_mm1_i386,
+ lldb_mm2_i386,
+ lldb_mm3_i386,
+ lldb_mm4_i386,
+ lldb_mm5_i386,
+ lldb_mm6_i386,
+ lldb_mm7_i386,
+ lldb_xmm0_i386,
+ lldb_xmm1_i386,
+ lldb_xmm2_i386,
+ lldb_xmm3_i386,
+ lldb_xmm4_i386,
+ lldb_xmm5_i386,
+ lldb_xmm6_i386,
+ lldb_xmm7_i386,
LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
-static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - 1 == k_num_fpr_registers_i386,
- "g_fpu_regnums_i386 has wrong number of register infos");
+static_assert((sizeof(g_lldb_regnums_i386) / sizeof(g_lldb_regnums_i386[0])) - 1 == k_num_fpr_registers_i386,
+ "g_lldb_regnums_i386 has wrong number of register infos");
const uint32_t
g_avx_regnums_i386[] =
{
- fpu_ymm0_i386,
- fpu_ymm1_i386,
- fpu_ymm2_i386,
- fpu_ymm3_i386,
- fpu_ymm4_i386,
- fpu_ymm5_i386,
- fpu_ymm6_i386,
- fpu_ymm7_i386,
+ lldb_ymm0_i386,
+ lldb_ymm1_i386,
+ lldb_ymm2_i386,
+ lldb_ymm3_i386,
+ lldb_ymm4_i386,
+ lldb_ymm5_i386,
+ lldb_ymm6_i386,
+ lldb_ymm7_i386,
LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 == k_num_avx_registers_i386,
@@ -128,212 +128,212 @@ static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 =
static const
uint32_t g_gpr_regnums_x86_64[] =
{
- gpr_rax_x86_64,
- gpr_rbx_x86_64,
- gpr_rcx_x86_64,
- gpr_rdx_x86_64,
- gpr_rdi_x86_64,
- gpr_rsi_x86_64,
- gpr_rbp_x86_64,
- gpr_rsp_x86_64,
- gpr_r8_x86_64,
- gpr_r9_x86_64,
- gpr_r10_x86_64,
- gpr_r11_x86_64,
- gpr_r12_x86_64,
- gpr_r13_x86_64,
- gpr_r14_x86_64,
- gpr_r15_x86_64,
- gpr_rip_x86_64,
- gpr_rflags_x86_64,
- gpr_cs_x86_64,
- gpr_fs_x86_64,
- gpr_gs_x86_64,
- gpr_ss_x86_64,
- gpr_ds_x86_64,
- gpr_es_x86_64,
- gpr_eax_x86_64,
- gpr_ebx_x86_64,
- gpr_ecx_x86_64,
- gpr_edx_x86_64,
- gpr_edi_x86_64,
- gpr_esi_x86_64,
- gpr_ebp_x86_64,
- gpr_esp_x86_64,
- gpr_r8d_x86_64, // Low 32 bits or r8
- gpr_r9d_x86_64, // Low 32 bits or r9
- gpr_r10d_x86_64, // Low 32 bits or r10
- gpr_r11d_x86_64, // Low 32 bits or r11
- gpr_r12d_x86_64, // Low 32 bits or r12
- gpr_r13d_x86_64, // Low 32 bits or r13
- gpr_r14d_x86_64, // Low 32 bits or r14
- gpr_r15d_x86_64, // Low 32 bits or r15
- gpr_ax_x86_64,
- gpr_bx_x86_64,
- gpr_cx_x86_64,
- gpr_dx_x86_64,
- gpr_di_x86_64,
- gpr_si_x86_64,
- gpr_bp_x86_64,
- gpr_sp_x86_64,
- gpr_r8w_x86_64, // Low 16 bits or r8
- gpr_r9w_x86_64, // Low 16 bits or r9
- gpr_r10w_x86_64, // Low 16 bits or r10
- gpr_r11w_x86_64, // Low 16 bits or r11
- gpr_r12w_x86_64, // Low 16 bits or r12
- gpr_r13w_x86_64, // Low 16 bits or r13
- gpr_r14w_x86_64, // Low 16 bits or r14
- gpr_r15w_x86_64, // Low 16 bits or r15
- gpr_ah_x86_64,
- gpr_bh_x86_64,
- gpr_ch_x86_64,
- gpr_dh_x86_64,
- gpr_al_x86_64,
- gpr_bl_x86_64,
- gpr_cl_x86_64,
- gpr_dl_x86_64,
- gpr_dil_x86_64,
- gpr_sil_x86_64,
- gpr_bpl_x86_64,
- gpr_spl_x86_64,
- gpr_r8l_x86_64, // Low 8 bits or r8
- gpr_r9l_x86_64, // Low 8 bits or r9
- gpr_r10l_x86_64, // Low 8 bits or r10
- gpr_r11l_x86_64, // Low 8 bits or r11
- gpr_r12l_x86_64, // Low 8 bits or r12
- gpr_r13l_x86_64, // Low 8 bits or r13
- gpr_r14l_x86_64, // Low 8 bits or r14
- gpr_r15l_x86_64, // Low 8 bits or r15
+ lldb_rax_x86_64,
+ lldb_rbx_x86_64,
+ lldb_rcx_x86_64,
+ lldb_rdx_x86_64,
+ lldb_rdi_x86_64,
+ lldb_rsi_x86_64,
+ lldb_rbp_x86_64,
+ lldb_rsp_x86_64,
+ lldb_r8_x86_64,
+ lldb_r9_x86_64,
+ lldb_r10_x86_64,
+ lldb_r11_x86_64,
+ lldb_r12_x86_64,
+ lldb_r13_x86_64,
+ lldb_r14_x86_64,
+ lldb_r15_x86_64,
+ lldb_rip_x86_64,
+ lldb_rflags_x86_64,
+ lldb_cs_x86_64,
+ lldb_fs_x86_64,
+ lldb_gs_x86_64,
+ lldb_ss_x86_64,
+ lldb_ds_x86_64,
+ lldb_es_x86_64,
+ lldb_eax_x86_64,
+ lldb_ebx_x86_64,
+ lldb_ecx_x86_64,
+ lldb_edx_x86_64,
+ lldb_edi_x86_64,
+ lldb_esi_x86_64,
+ lldb_ebp_x86_64,
+ lldb_esp_x86_64,
+ lldb_r8d_x86_64, // Low 32 bits or r8
+ lldb_r9d_x86_64, // Low 32 bits or r9
+ lldb_r10d_x86_64, // Low 32 bits or r10
+ lldb_r11d_x86_64, // Low 32 bits or r11
+ lldb_r12d_x86_64, // Low 32 bits or r12
+ lldb_r13d_x86_64, // Low 32 bits or r13
+ lldb_r14d_x86_64, // Low 32 bits or r14
+ lldb_r15d_x86_64, // Low 32 bits or r15
+ lldb_ax_x86_64,
+ lldb_bx_x86_64,
+ lldb_cx_x86_64,
+ lldb_dx_x86_64,
+ lldb_di_x86_64,
+ lldb_si_x86_64,
+ lldb_bp_x86_64,
+ lldb_sp_x86_64,
+ lldb_r8w_x86_64, // Low 16 bits or r8
+ lldb_r9w_x86_64, // Low 16 bits or r9
+ lldb_r10w_x86_64, // Low 16 bits or r10
+ lldb_r11w_x86_64, // Low 16 bits or r11
+ lldb_r12w_x86_64, // Low 16 bits or r12
+ lldb_r13w_x86_64, // Low 16 bits or r13
+ lldb_r14w_x86_64, // Low 16 bits or r14
+ lldb_r15w_x86_64, // Low 16 bits or r15
+ lldb_ah_x86_64,
+ lldb_bh_x86_64,
+ lldb_ch_x86_64,
+ lldb_dh_x86_64,
+ lldb_al_x86_64,
+ lldb_bl_x86_64,
+ lldb_cl_x86_64,
+ lldb_dl_x86_64,
+ lldb_dil_x86_64,
+ lldb_sil_x86_64,
+ lldb_bpl_x86_64,
+ lldb_spl_x86_64,
+ lldb_r8l_x86_64, // Low 8 bits or r8
+ lldb_r9l_x86_64, // Low 8 bits or r9
+ lldb_r10l_x86_64, // Low 8 bits or r10
+ lldb_r11l_x86_64, // Low 8 bits or r11
+ lldb_r12l_x86_64, // Low 8 bits or r12
+ lldb_r13l_x86_64, // Low 8 bits or r13
+ lldb_r14l_x86_64, // Low 8 bits or r14
+ lldb_r15l_x86_64, // Low 8 bits or r15
LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - 1 == k_num_gpr_registers_x86_64,
"g_gpr_regnums_x86_64 has wrong number of register infos");
static const uint32_t
-g_fpu_regnums_x86_64[] =
-{
- fpu_fctrl_x86_64,
- fpu_fstat_x86_64,
- fpu_ftag_x86_64,
- fpu_fop_x86_64,
- fpu_fiseg_x86_64,
- fpu_fioff_x86_64,
- fpu_foseg_x86_64,
- fpu_fooff_x86_64,
- fpu_mxcsr_x86_64,
- fpu_mxcsrmask_x86_64,
- fpu_st0_x86_64,
- fpu_st1_x86_64,
- fpu_st2_x86_64,
- fpu_st3_x86_64,
- fpu_st4_x86_64,
- fpu_st5_x86_64,
- fpu_st6_x86_64,
- fpu_st7_x86_64,
- fpu_mm0_x86_64,
- fpu_mm1_x86_64,
- fpu_mm2_x86_64,
- fpu_mm3_x86_64,
- fpu_mm4_x86_64,
- fpu_mm5_x86_64,
- fpu_mm6_x86_64,
- fpu_mm7_x86_64,
- fpu_xmm0_x86_64,
- fpu_xmm1_x86_64,
- fpu_xmm2_x86_64,
- fpu_xmm3_x86_64,
- fpu_xmm4_x86_64,
- fpu_xmm5_x86_64,
- fpu_xmm6_x86_64,
- fpu_xmm7_x86_64,
- fpu_xmm8_x86_64,
- fpu_xmm9_x86_64,
- fpu_xmm10_x86_64,
- fpu_xmm11_x86_64,
- fpu_xmm12_x86_64,
- fpu_xmm13_x86_64,
- fpu_xmm14_x86_64,
- fpu_xmm15_x86_64,
+g_lldb_regnums_x86_64[] =
+{
+ lldb_fctrl_x86_64,
+ lldb_fstat_x86_64,
+ lldb_ftag_x86_64,
+ lldb_fop_x86_64,
+ lldb_fiseg_x86_64,
+ lldb_fioff_x86_64,
+ lldb_foseg_x86_64,
+ lldb_fooff_x86_64,
+ lldb_mxcsr_x86_64,
+ lldb_mxcsrmask_x86_64,
+ lldb_st0_x86_64,
+ lldb_st1_x86_64,
+ lldb_st2_x86_64,
+ lldb_st3_x86_64,
+ lldb_st4_x86_64,
+ lldb_st5_x86_64,
+ lldb_st6_x86_64,
+ lldb_st7_x86_64,
+ lldb_mm0_x86_64,
+ lldb_mm1_x86_64,
+ lldb_mm2_x86_64,
+ lldb_mm3_x86_64,
+ lldb_mm4_x86_64,
+ lldb_mm5_x86_64,
+ lldb_mm6_x86_64,
+ lldb_mm7_x86_64,
+ lldb_xmm0_x86_64,
+ lldb_xmm1_x86_64,
+ lldb_xmm2_x86_64,
+ lldb_xmm3_x86_64,
+ lldb_xmm4_x86_64,
+ lldb_xmm5_x86_64,
+ lldb_xmm6_x86_64,
+ lldb_xmm7_x86_64,
+ lldb_xmm8_x86_64,
+ lldb_xmm9_x86_64,
+ lldb_xmm10_x86_64,
+ lldb_xmm11_x86_64,
+ lldb_xmm12_x86_64,
+ lldb_xmm13_x86_64,
+ lldb_xmm14_x86_64,
+ lldb_xmm15_x86_64,
LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
-static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - 1 == k_num_fpr_registers_x86_64,
- "g_fpu_regnums_x86_64 has wrong number of register infos");
+static_assert((sizeof(g_lldb_regnums_x86_64) / sizeof(g_lldb_regnums_x86_64[0])) - 1 == k_num_fpr_registers_x86_64,
+ "g_lldb_regnums_x86_64 has wrong number of register infos");
static const uint32_t
g_avx_regnums_x86_64[] =
{
- fpu_ymm0_x86_64,
- fpu_ymm1_x86_64,
- fpu_ymm2_x86_64,
- fpu_ymm3_x86_64,
- fpu_ymm4_x86_64,
- fpu_ymm5_x86_64,
- fpu_ymm6_x86_64,
- fpu_ymm7_x86_64,
- fpu_ymm8_x86_64,
- fpu_ymm9_x86_64,
- fpu_ymm10_x86_64,
- fpu_ymm11_x86_64,
- fpu_ymm12_x86_64,
- fpu_ymm13_x86_64,
- fpu_ymm14_x86_64,
- fpu_ymm15_x86_64,
+ lldb_ymm0_x86_64,
+ lldb_ymm1_x86_64,
+ lldb_ymm2_x86_64,
+ lldb_ymm3_x86_64,
+ lldb_ymm4_x86_64,
+ lldb_ymm5_x86_64,
+ lldb_ymm6_x86_64,
+ lldb_ymm7_x86_64,
+ lldb_ymm8_x86_64,
+ lldb_ymm9_x86_64,
+ lldb_ymm10_x86_64,
+ lldb_ymm11_x86_64,
+ lldb_ymm12_x86_64,
+ lldb_ymm13_x86_64,
+ lldb_ymm14_x86_64,
+ lldb_ymm15_x86_64,
LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - 1 == k_num_avx_registers_x86_64,
"g_avx_regnums_x86_64 has wrong number of register infos");
-uint32_t RegisterContextPOSIX_x86::g_contained_eax[] = { gpr_eax_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_ebx[] = { gpr_ebx_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_ecx[] = { gpr_ecx_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_edx[] = { gpr_edx_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_edi[] = { gpr_edi_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_esi[] = { gpr_esi_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_ebp[] = { gpr_ebp_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_esp[] = { gpr_esp_i386, LLDB_INVALID_REGNUM };
-
-uint32_t RegisterContextPOSIX_x86::g_invalidate_eax[] = { gpr_eax_i386, gpr_ax_i386, gpr_ah_i386, gpr_al_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_ebx[] = { gpr_ebx_i386, gpr_bx_i386, gpr_bh_i386, gpr_bl_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_ecx[] = { gpr_ecx_i386, gpr_cx_i386, gpr_ch_i386, gpr_cl_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_edx[] = { gpr_edx_i386, gpr_dx_i386, gpr_dh_i386, gpr_dl_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_edi[] = { gpr_edi_i386, gpr_di_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_esi[] = { gpr_esi_i386, gpr_si_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_ebp[] = { gpr_ebp_i386, gpr_bp_i386, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_esp[] = { gpr_esp_i386, gpr_sp_i386, LLDB_INVALID_REGNUM };
-
-uint32_t RegisterContextPOSIX_x86::g_contained_rax[] = { gpr_rax_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_rbx[] = { gpr_rbx_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_rcx[] = { gpr_rcx_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_rdx[] = { gpr_rdx_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_rdi[] = { gpr_rdi_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_rsi[] = { gpr_rsi_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_rbp[] = { gpr_rbp_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_rsp[] = { gpr_rsp_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_r8[] = { gpr_r8_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_r9[] = { gpr_r9_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_r10[] = { gpr_r10_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_r11[] = { gpr_r11_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_r12[] = { gpr_r12_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_r13[] = { gpr_r13_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_r14[] = { gpr_r14_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_contained_r15[] = { gpr_r15_x86_64, LLDB_INVALID_REGNUM };
-
-uint32_t RegisterContextPOSIX_x86::g_invalidate_rax[] = { gpr_rax_x86_64, gpr_eax_x86_64, gpr_ax_x86_64, gpr_ah_x86_64, gpr_al_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_rbx[] = { gpr_rbx_x86_64, gpr_ebx_x86_64, gpr_bx_x86_64, gpr_bh_x86_64, gpr_bl_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_rcx[] = { gpr_rcx_x86_64, gpr_ecx_x86_64, gpr_cx_x86_64, gpr_ch_x86_64, gpr_cl_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_rdx[] = { gpr_rdx_x86_64, gpr_edx_x86_64, gpr_dx_x86_64, gpr_dh_x86_64, gpr_dl_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_rdi[] = { gpr_rdi_x86_64, gpr_edi_x86_64, gpr_di_x86_64, gpr_dil_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_rsi[] = { gpr_rsi_x86_64, gpr_esi_x86_64, gpr_si_x86_64, gpr_sil_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_rbp[] = { gpr_rbp_x86_64, gpr_ebp_x86_64, gpr_bp_x86_64, gpr_bpl_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_rsp[] = { gpr_rsp_x86_64, gpr_esp_x86_64, gpr_sp_x86_64, gpr_spl_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_r8[] = { gpr_r8_x86_64, gpr_r8d_x86_64, gpr_r8w_x86_64, gpr_r8l_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_r9[] = { gpr_r9_x86_64, gpr_r9d_x86_64, gpr_r9w_x86_64, gpr_r9l_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_r10[] = { gpr_r10_x86_64, gpr_r10d_x86_64, gpr_r10w_x86_64, gpr_r10l_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_r11[] = { gpr_r11_x86_64, gpr_r11d_x86_64, gpr_r11w_x86_64, gpr_r11l_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_r12[] = { gpr_r12_x86_64, gpr_r12d_x86_64, gpr_r12w_x86_64, gpr_r12l_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_r13[] = { gpr_r13_x86_64, gpr_r13d_x86_64, gpr_r13w_x86_64, gpr_r13l_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_r14[] = { gpr_r14_x86_64, gpr_r14d_x86_64, gpr_r14w_x86_64, gpr_r14l_x86_64, LLDB_INVALID_REGNUM };
-uint32_t RegisterContextPOSIX_x86::g_invalidate_r15[] = { gpr_r15_x86_64, gpr_r15d_x86_64, gpr_r15w_x86_64, gpr_r15l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_eax[] = { lldb_eax_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_ebx[] = { lldb_ebx_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_ecx[] = { lldb_ecx_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_edx[] = { lldb_edx_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_edi[] = { lldb_edi_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_esi[] = { lldb_esi_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_ebp[] = { lldb_ebp_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_esp[] = { lldb_esp_i386, LLDB_INVALID_REGNUM };
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_eax[] = { lldb_eax_i386, lldb_ax_i386, lldb_ah_i386, lldb_al_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_ebx[] = { lldb_ebx_i386, lldb_bx_i386, lldb_bh_i386, lldb_bl_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_ecx[] = { lldb_ecx_i386, lldb_cx_i386, lldb_ch_i386, lldb_cl_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_edx[] = { lldb_edx_i386, lldb_dx_i386, lldb_dh_i386, lldb_dl_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_edi[] = { lldb_edi_i386, lldb_di_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_esi[] = { lldb_esi_i386, lldb_si_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_ebp[] = { lldb_ebp_i386, lldb_bp_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_esp[] = { lldb_esp_i386, lldb_sp_i386, LLDB_INVALID_REGNUM };
+
+uint32_t RegisterContextPOSIX_x86::g_contained_rax[] = { lldb_rax_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rbx[] = { lldb_rbx_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rcx[] = { lldb_rcx_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rdx[] = { lldb_rdx_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rdi[] = { lldb_rdi_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rsi[] = { lldb_rsi_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rbp[] = { lldb_rbp_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rsp[] = { lldb_rsp_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r8[] = { lldb_r8_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r9[] = { lldb_r9_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r10[] = { lldb_r10_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r11[] = { lldb_r11_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r12[] = { lldb_r12_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r13[] = { lldb_r13_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r14[] = { lldb_r14_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r15[] = { lldb_r15_x86_64, LLDB_INVALID_REGNUM };
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rax[] = { lldb_rax_x86_64, lldb_eax_x86_64, lldb_ax_x86_64, lldb_ah_x86_64, lldb_al_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rbx[] = { lldb_rbx_x86_64, lldb_ebx_x86_64, lldb_bx_x86_64, lldb_bh_x86_64, lldb_bl_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rcx[] = { lldb_rcx_x86_64, lldb_ecx_x86_64, lldb_cx_x86_64, lldb_ch_x86_64, lldb_cl_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rdx[] = { lldb_rdx_x86_64, lldb_edx_x86_64, lldb_dx_x86_64, lldb_dh_x86_64, lldb_dl_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rdi[] = { lldb_rdi_x86_64, lldb_edi_x86_64, lldb_di_x86_64, lldb_dil_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rsi[] = { lldb_rsi_x86_64, lldb_esi_x86_64, lldb_si_x86_64, lldb_sil_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rbp[] = { lldb_rbp_x86_64, lldb_ebp_x86_64, lldb_bp_x86_64, lldb_bpl_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rsp[] = { lldb_rsp_x86_64, lldb_esp_x86_64, lldb_sp_x86_64, lldb_spl_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r8[] = { lldb_r8_x86_64, lldb_r8d_x86_64, lldb_r8w_x86_64, lldb_r8l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r9[] = { lldb_r9_x86_64, lldb_r9d_x86_64, lldb_r9w_x86_64, lldb_r9l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r10[] = { lldb_r10_x86_64, lldb_r10d_x86_64, lldb_r10w_x86_64, lldb_r10l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r11[] = { lldb_r11_x86_64, lldb_r11d_x86_64, lldb_r11w_x86_64, lldb_r11l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r12[] = { lldb_r12_x86_64, lldb_r12d_x86_64, lldb_r12w_x86_64, lldb_r12l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r13[] = { lldb_r13_x86_64, lldb_r13d_x86_64, lldb_r13w_x86_64, lldb_r13l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r14[] = { lldb_r14_x86_64, lldb_r14d_x86_64, lldb_r14w_x86_64, lldb_r14l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r15[] = { lldb_r15_x86_64, lldb_r15d_x86_64, lldb_r15w_x86_64, lldb_r15l_x86_64, LLDB_INVALID_REGNUM };
// Number of register sets provided by this context.
enum
@@ -346,7 +346,7 @@ static const RegisterSet
g_reg_sets_i386[k_num_register_sets] =
{
{ "General Purpose Registers", "gpr", k_num_gpr_registers_i386, g_gpr_regnums_i386 },
- { "Floating Point Registers", "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386 },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_i386, g_lldb_regnums_i386 },
{ "Advanced Vector Extensions", "avx", k_num_avx_registers_i386, g_avx_regnums_i386 }
};
@@ -354,7 +354,7 @@ static const RegisterSet
g_reg_sets_x86_64[k_num_register_sets] =
{
{ "General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64 },
- { "Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64 },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, g_lldb_regnums_x86_64 },
{ "Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, g_avx_regnums_x86_64 }
};
@@ -399,16 +399,16 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread,
m_reg_info.last_gpr = k_last_gpr_i386;
m_reg_info.first_fpr = k_first_fpr_i386;
m_reg_info.last_fpr = k_last_fpr_i386;
- m_reg_info.first_st = fpu_st0_i386;
- m_reg_info.last_st = fpu_st7_i386;
- m_reg_info.first_mm = fpu_mm0_i386;
- m_reg_info.last_mm = fpu_mm7_i386;
- m_reg_info.first_xmm = fpu_xmm0_i386;
- m_reg_info.last_xmm = fpu_xmm7_i386;
- m_reg_info.first_ymm = fpu_ymm0_i386;
- m_reg_info.last_ymm = fpu_ymm7_i386;
- m_reg_info.first_dr = dr0_i386;
- m_reg_info.gpr_flags = gpr_eflags_i386;
+ m_reg_info.first_st = lldb_st0_i386;
+ m_reg_info.last_st = lldb_st7_i386;
+ m_reg_info.first_mm = lldb_mm0_i386;
+ m_reg_info.last_mm = lldb_mm7_i386;
+ m_reg_info.first_xmm = lldb_xmm0_i386;
+ m_reg_info.last_xmm = lldb_xmm7_i386;
+ m_reg_info.first_ymm = lldb_ymm0_i386;
+ m_reg_info.last_ymm = lldb_ymm7_i386;
+ m_reg_info.first_dr = lldb_dr0_i386;
+ m_reg_info.gpr_flags = lldb_eflags_i386;
break;
case llvm::Triple::x86_64:
m_reg_info.num_registers = k_num_registers_x86_64;
@@ -418,16 +418,16 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread,
m_reg_info.last_gpr = k_last_gpr_x86_64;
m_reg_info.first_fpr = k_first_fpr_x86_64;
m_reg_info.last_fpr = k_last_fpr_x86_64;
- m_reg_info.first_st = fpu_st0_x86_64;
- m_reg_info.last_st = fpu_st7_x86_64;
- m_reg_info.first_mm = fpu_mm0_x86_64;
- m_reg_info.last_mm = fpu_mm7_x86_64;
- m_reg_info.first_xmm = fpu_xmm0_x86_64;
- m_reg_info.last_xmm = fpu_xmm15_x86_64;
- m_reg_info.first_ymm = fpu_ymm0_x86_64;
- m_reg_info.last_ymm = fpu_ymm15_x86_64;
- m_reg_info.first_dr = dr0_x86_64;
- m_reg_info.gpr_flags = gpr_rflags_x86_64;
+ m_reg_info.first_st = lldb_st0_x86_64;
+ m_reg_info.last_st = lldb_st7_x86_64;
+ m_reg_info.first_mm = lldb_mm0_x86_64;
+ m_reg_info.last_mm = lldb_mm7_x86_64;
+ m_reg_info.first_xmm = lldb_xmm0_x86_64;
+ m_reg_info.last_xmm = lldb_xmm15_x86_64;
+ m_reg_info.first_ymm = lldb_ymm0_x86_64;
+ m_reg_info.last_ymm = lldb_ymm15_x86_64;
+ m_reg_info.first_dr = lldb_dr0_x86_64;
+ m_reg_info.gpr_flags = lldb_rflags_x86_64;
break;
default:
assert(false && "Unhandled target architecture.");
diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
index 4db7802e1b44..0eec1d909c1a 100644
--- a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
@@ -11,285 +11,12 @@
#define liblldb_RegisterContextPOSIX_x86_H_
#include "lldb/Core/Log.h"
+#include "lldb-x86-register-enums.h"
#include "RegisterContextPOSIX.h"
#include "RegisterContext_x86.h"
class ProcessMonitor;
-//---------------------------------------------------------------------------
-// Internal codes for all i386 registers.
-//---------------------------------------------------------------------------
-enum
-{
- k_first_gpr_i386,
- gpr_eax_i386 = k_first_gpr_i386,
- gpr_ebx_i386,
- gpr_ecx_i386,
- gpr_edx_i386,
- gpr_edi_i386,
- gpr_esi_i386,
- gpr_ebp_i386,
- gpr_esp_i386,
- gpr_eip_i386,
- gpr_eflags_i386,
- gpr_cs_i386,
- gpr_fs_i386,
- gpr_gs_i386,
- gpr_ss_i386,
- gpr_ds_i386,
- gpr_es_i386,
-
- k_first_alias_i386,
- gpr_ax_i386 = k_first_alias_i386,
- gpr_bx_i386,
- gpr_cx_i386,
- gpr_dx_i386,
- gpr_di_i386,
- gpr_si_i386,
- gpr_bp_i386,
- gpr_sp_i386,
- gpr_ah_i386,
- gpr_bh_i386,
- gpr_ch_i386,
- gpr_dh_i386,
- gpr_al_i386,
- gpr_bl_i386,
- gpr_cl_i386,
- gpr_dl_i386,
- k_last_alias_i386 = gpr_dl_i386,
-
- k_last_gpr_i386 = k_last_alias_i386,
-
- k_first_fpr_i386,
- fpu_fctrl_i386 = k_first_fpr_i386,
- fpu_fstat_i386,
- fpu_ftag_i386,
- fpu_fop_i386,
- fpu_fiseg_i386,
- fpu_fioff_i386,
- fpu_foseg_i386,
- fpu_fooff_i386,
- fpu_mxcsr_i386,
- fpu_mxcsrmask_i386,
- fpu_st0_i386,
- fpu_st1_i386,
- fpu_st2_i386,
- fpu_st3_i386,
- fpu_st4_i386,
- fpu_st5_i386,
- fpu_st6_i386,
- fpu_st7_i386,
- fpu_mm0_i386,
- fpu_mm1_i386,
- fpu_mm2_i386,
- fpu_mm3_i386,
- fpu_mm4_i386,
- fpu_mm5_i386,
- fpu_mm6_i386,
- fpu_mm7_i386,
- fpu_xmm0_i386,
- fpu_xmm1_i386,
- fpu_xmm2_i386,
- fpu_xmm3_i386,
- fpu_xmm4_i386,
- fpu_xmm5_i386,
- fpu_xmm6_i386,
- fpu_xmm7_i386,
- k_last_fpr_i386 = fpu_xmm7_i386,
-
- k_first_avx_i386,
- fpu_ymm0_i386 = k_first_avx_i386,
- fpu_ymm1_i386,
- fpu_ymm2_i386,
- fpu_ymm3_i386,
- fpu_ymm4_i386,
- fpu_ymm5_i386,
- fpu_ymm6_i386,
- fpu_ymm7_i386,
- k_last_avx_i386 = fpu_ymm7_i386,
-
- dr0_i386,
- dr1_i386,
- dr2_i386,
- dr3_i386,
- dr4_i386,
- dr5_i386,
- dr6_i386,
- dr7_i386,
-
- k_num_registers_i386,
- k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1,
- k_num_fpr_registers_i386 = k_last_fpr_i386 - k_first_fpr_i386 + 1,
- k_num_avx_registers_i386 = k_last_avx_i386 - k_first_avx_i386 + 1
-};
-
-//---------------------------------------------------------------------------
-// Internal codes for all x86_64 registers.
-//---------------------------------------------------------------------------
-enum
-{
- k_first_gpr_x86_64,
- gpr_rax_x86_64 = k_first_gpr_x86_64,
- gpr_rbx_x86_64,
- gpr_rcx_x86_64,
- gpr_rdx_x86_64,
- gpr_rdi_x86_64,
- gpr_rsi_x86_64,
- gpr_rbp_x86_64,
- gpr_rsp_x86_64,
- gpr_r8_x86_64,
- gpr_r9_x86_64,
- gpr_r10_x86_64,
- gpr_r11_x86_64,
- gpr_r12_x86_64,
- gpr_r13_x86_64,
- gpr_r14_x86_64,
- gpr_r15_x86_64,
- gpr_rip_x86_64,
- gpr_rflags_x86_64,
- gpr_cs_x86_64,
- gpr_fs_x86_64,
- gpr_gs_x86_64,
- gpr_ss_x86_64,
- gpr_ds_x86_64,
- gpr_es_x86_64,
-
- k_first_alias_x86_64,
- gpr_eax_x86_64 = k_first_alias_x86_64,
- gpr_ebx_x86_64,
- gpr_ecx_x86_64,
- gpr_edx_x86_64,
- gpr_edi_x86_64,
- gpr_esi_x86_64,
- gpr_ebp_x86_64,
- gpr_esp_x86_64,
- gpr_r8d_x86_64, // Low 32 bits of r8
- gpr_r9d_x86_64, // Low 32 bits of r9
- gpr_r10d_x86_64, // Low 32 bits of r10
- gpr_r11d_x86_64, // Low 32 bits of r11
- gpr_r12d_x86_64, // Low 32 bits of r12
- gpr_r13d_x86_64, // Low 32 bits of r13
- gpr_r14d_x86_64, // Low 32 bits of r14
- gpr_r15d_x86_64, // Low 32 bits of r15
- gpr_ax_x86_64,
- gpr_bx_x86_64,
- gpr_cx_x86_64,
- gpr_dx_x86_64,
- gpr_di_x86_64,
- gpr_si_x86_64,
- gpr_bp_x86_64,
- gpr_sp_x86_64,
- gpr_r8w_x86_64, // Low 16 bits of r8
- gpr_r9w_x86_64, // Low 16 bits of r9
- gpr_r10w_x86_64, // Low 16 bits of r10
- gpr_r11w_x86_64, // Low 16 bits of r11
- gpr_r12w_x86_64, // Low 16 bits of r12
- gpr_r13w_x86_64, // Low 16 bits of r13
- gpr_r14w_x86_64, // Low 16 bits of r14
- gpr_r15w_x86_64, // Low 16 bits of r15
- gpr_ah_x86_64,
- gpr_bh_x86_64,
- gpr_ch_x86_64,
- gpr_dh_x86_64,
- gpr_al_x86_64,
- gpr_bl_x86_64,
- gpr_cl_x86_64,
- gpr_dl_x86_64,
- gpr_dil_x86_64,
- gpr_sil_x86_64,
- gpr_bpl_x86_64,
- gpr_spl_x86_64,
- gpr_r8l_x86_64, // Low 8 bits of r8
- gpr_r9l_x86_64, // Low 8 bits of r9
- gpr_r10l_x86_64, // Low 8 bits of r10
- gpr_r11l_x86_64, // Low 8 bits of r11
- gpr_r12l_x86_64, // Low 8 bits of r12
- gpr_r13l_x86_64, // Low 8 bits of r13
- gpr_r14l_x86_64, // Low 8 bits of r14
- gpr_r15l_x86_64, // Low 8 bits of r15
- k_last_alias_x86_64 = gpr_r15l_x86_64,
-
- k_last_gpr_x86_64 = k_last_alias_x86_64,
-
- k_first_fpr_x86_64,
- fpu_fctrl_x86_64 = k_first_fpr_x86_64,
- fpu_fstat_x86_64,
- fpu_ftag_x86_64,
- fpu_fop_x86_64,
- fpu_fiseg_x86_64,
- fpu_fioff_x86_64,
- fpu_foseg_x86_64,
- fpu_fooff_x86_64,
- fpu_mxcsr_x86_64,
- fpu_mxcsrmask_x86_64,
- fpu_st0_x86_64,
- fpu_st1_x86_64,
- fpu_st2_x86_64,
- fpu_st3_x86_64,
- fpu_st4_x86_64,
- fpu_st5_x86_64,
- fpu_st6_x86_64,
- fpu_st7_x86_64,
- fpu_mm0_x86_64,
- fpu_mm1_x86_64,
- fpu_mm2_x86_64,
- fpu_mm3_x86_64,
- fpu_mm4_x86_64,
- fpu_mm5_x86_64,
- fpu_mm6_x86_64,
- fpu_mm7_x86_64,
- fpu_xmm0_x86_64,
- fpu_xmm1_x86_64,
- fpu_xmm2_x86_64,
- fpu_xmm3_x86_64,
- fpu_xmm4_x86_64,
- fpu_xmm5_x86_64,
- fpu_xmm6_x86_64,
- fpu_xmm7_x86_64,
- fpu_xmm8_x86_64,
- fpu_xmm9_x86_64,
- fpu_xmm10_x86_64,
- fpu_xmm11_x86_64,
- fpu_xmm12_x86_64,
- fpu_xmm13_x86_64,
- fpu_xmm14_x86_64,
- fpu_xmm15_x86_64,
- k_last_fpr_x86_64 = fpu_xmm15_x86_64,
-
- k_first_avx_x86_64,
- fpu_ymm0_x86_64 = k_first_avx_x86_64,
- fpu_ymm1_x86_64,
- fpu_ymm2_x86_64,
- fpu_ymm3_x86_64,
- fpu_ymm4_x86_64,
- fpu_ymm5_x86_64,
- fpu_ymm6_x86_64,
- fpu_ymm7_x86_64,
- fpu_ymm8_x86_64,
- fpu_ymm9_x86_64,
- fpu_ymm10_x86_64,
- fpu_ymm11_x86_64,
- fpu_ymm12_x86_64,
- fpu_ymm13_x86_64,
- fpu_ymm14_x86_64,
- fpu_ymm15_x86_64,
- k_last_avx_x86_64 = fpu_ymm15_x86_64,
-
- dr0_x86_64,
- dr1_x86_64,
- dr2_x86_64,
- dr3_x86_64,
- dr4_x86_64,
- dr5_x86_64,
- dr6_x86_64,
- dr7_x86_64,
-
- k_num_registers_x86_64,
- k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1,
- k_num_fpr_registers_x86_64 = k_last_fpr_x86_64 - k_first_fpr_x86_64 + 1,
- k_num_avx_registers_x86_64 = k_last_avx_x86_64 - k_first_avx_x86_64 + 1
-};
-
class RegisterContextPOSIX_x86
: public lldb_private::RegisterContext
{
@@ -422,7 +149,7 @@ protected:
uint32_t gpr_flags;
};
- uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64]; // 64-bit general purpose registers.
+ uint64_t m_gpr_x86_64[lldb_private::k_num_gpr_registers_x86_64]; // 64-bit general purpose registers.
RegInfo m_reg_info;
FPRType m_fpr_type; // determines the type of data stored by union FPR, if any.
FPR m_fpr; // floating-point registers including extended register sets.
diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
index 46dafa11d8f7..200ef4d3d651 100644
--- a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
@@ -59,7 +59,7 @@ RegisterContextThreadMemory::UpdateRegisterContext ()
{
OperatingSystem *os = process_sp->GetOperatingSystem ();
if (os->IsOperatingSystemPluginThread (thread_sp))
- m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), LLDB_INVALID_ADDRESS);
+ m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), m_register_data_addr);
}
}
}
diff --git a/source/Plugins/Process/Utility/RegisterContext_powerpc.h b/source/Plugins/Process/Utility/RegisterContext_powerpc.h
new file mode 100644
index 000000000000..cf54cc0c2145
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContext_powerpc.h
@@ -0,0 +1,163 @@
+//===-- RegisterContext_powerpc.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_RegisterContext_powerpc_H_
+#define liblldb_RegisterContext_powerpc_H_
+
+// GCC and DWARF Register numbers (eRegisterKindGCC & eRegisterKindDWARF)
+enum
+{
+ gcc_dwarf_r0_powerpc = 0,
+ gcc_dwarf_r1_powerpc,
+ gcc_dwarf_r2_powerpc,
+ gcc_dwarf_r3_powerpc,
+ gcc_dwarf_r4_powerpc,
+ gcc_dwarf_r5_powerpc,
+ gcc_dwarf_r6_powerpc,
+ gcc_dwarf_r7_powerpc,
+ gcc_dwarf_r8_powerpc,
+ gcc_dwarf_r9_powerpc,
+ gcc_dwarf_r10_powerpc,
+ gcc_dwarf_r11_powerpc,
+ gcc_dwarf_r12_powerpc,
+ gcc_dwarf_r13_powerpc,
+ gcc_dwarf_r14_powerpc,
+ gcc_dwarf_r15_powerpc,
+ gcc_dwarf_r16_powerpc,
+ gcc_dwarf_r17_powerpc,
+ gcc_dwarf_r18_powerpc,
+ gcc_dwarf_r19_powerpc,
+ gcc_dwarf_r20_powerpc,
+ gcc_dwarf_r21_powerpc,
+ gcc_dwarf_r22_powerpc,
+ gcc_dwarf_r23_powerpc,
+ gcc_dwarf_r24_powerpc,
+ gcc_dwarf_r25_powerpc,
+ gcc_dwarf_r26_powerpc,
+ gcc_dwarf_r27_powerpc,
+ gcc_dwarf_r28_powerpc,
+ gcc_dwarf_r29_powerpc,
+ gcc_dwarf_r30_powerpc,
+ gcc_dwarf_r31_powerpc,
+ gcc_dwarf_f0_powerpc,
+ gcc_dwarf_f1_powerpc,
+ gcc_dwarf_f2_powerpc,
+ gcc_dwarf_f3_powerpc,
+ gcc_dwarf_f4_powerpc,
+ gcc_dwarf_f5_powerpc,
+ gcc_dwarf_f6_powerpc,
+ gcc_dwarf_f7_powerpc,
+ gcc_dwarf_f8_powerpc,
+ gcc_dwarf_f9_powerpc,
+ gcc_dwarf_f10_powerpc,
+ gcc_dwarf_f11_powerpc,
+ gcc_dwarf_f12_powerpc,
+ gcc_dwarf_f13_powerpc,
+ gcc_dwarf_f14_powerpc,
+ gcc_dwarf_f15_powerpc,
+ gcc_dwarf_f16_powerpc,
+ gcc_dwarf_f17_powerpc,
+ gcc_dwarf_f18_powerpc,
+ gcc_dwarf_f19_powerpc,
+ gcc_dwarf_f20_powerpc,
+ gcc_dwarf_f21_powerpc,
+ gcc_dwarf_f22_powerpc,
+ gcc_dwarf_f23_powerpc,
+ gcc_dwarf_f24_powerpc,
+ gcc_dwarf_f25_powerpc,
+ gcc_dwarf_f26_powerpc,
+ gcc_dwarf_f27_powerpc,
+ gcc_dwarf_f28_powerpc,
+ gcc_dwarf_f29_powerpc,
+ gcc_dwarf_f30_powerpc,
+ gcc_dwarf_f31_powerpc,
+ gcc_dwarf_cr_powerpc,
+ gcc_dwarf_fpscr_powerpc,
+ gcc_dwarf_xer_powerpc = 101,
+ gcc_dwarf_lr_powerpc = 108,
+ gcc_dwarf_ctr_powerpc,
+ gcc_dwarf_pc_powerpc,
+};
+
+// GDB Register numbers (eRegisterKindGDB)
+enum
+{
+ gdb_r0_powerpc = 0,
+ gdb_r1_powerpc,
+ gdb_r2_powerpc,
+ gdb_r3_powerpc,
+ gdb_r4_powerpc,
+ gdb_r5_powerpc,
+ gdb_r6_powerpc,
+ gdb_r7_powerpc,
+ gdb_r8_powerpc,
+ gdb_r9_powerpc,
+ gdb_r10_powerpc,
+ gdb_r11_powerpc,
+ gdb_r12_powerpc,
+ gdb_r13_powerpc,
+ gdb_r14_powerpc,
+ gdb_r15_powerpc,
+ gdb_r16_powerpc,
+ gdb_r17_powerpc,
+ gdb_r18_powerpc,
+ gdb_r19_powerpc,
+ gdb_r20_powerpc,
+ gdb_r21_powerpc,
+ gdb_r22_powerpc,
+ gdb_r23_powerpc,
+ gdb_r24_powerpc,
+ gdb_r25_powerpc,
+ gdb_r26_powerpc,
+ gdb_r27_powerpc,
+ gdb_r28_powerpc,
+ gdb_r29_powerpc,
+ gdb_r30_powerpc,
+ gdb_r31_powerpc,
+ gdb_f0_powerpc,
+ gdb_f1_powerpc,
+ gdb_f2_powerpc,
+ gdb_f3_powerpc,
+ gdb_f4_powerpc,
+ gdb_f5_powerpc,
+ gdb_f6_powerpc,
+ gdb_f7_powerpc,
+ gdb_f8_powerpc,
+ gdb_f9_powerpc,
+ gdb_f10_powerpc,
+ gdb_f11_powerpc,
+ gdb_f12_powerpc,
+ gdb_f13_powerpc,
+ gdb_f14_powerpc,
+ gdb_f15_powerpc,
+ gdb_f16_powerpc,
+ gdb_f17_powerpc,
+ gdb_f18_powerpc,
+ gdb_f19_powerpc,
+ gdb_f20_powerpc,
+ gdb_f21_powerpc,
+ gdb_f22_powerpc,
+ gdb_f23_powerpc,
+ gdb_f24_powerpc,
+ gdb_f25_powerpc,
+ gdb_f26_powerpc,
+ gdb_f27_powerpc,
+ gdb_f28_powerpc,
+ gdb_f29_powerpc,
+ gdb_f30_powerpc,
+ gdb_f31_powerpc,
+ gdb_cr_powerpc,
+ gdb_fpscr_powerpc,
+ gdb_xer_powerpc = 101,
+ gdb_lr_powerpc = 108,
+ gdb_ctr_powerpc,
+ gdb_pc_powerpc,
+};
+
+#endif // liblldb_RegisterContext_powerpc_H_
diff --git a/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/source/Plugins/Process/Utility/RegisterInfos_arm64.h
index 1bb4e89c8f78..b687423622a4 100644
--- a/source/Plugins/Process/Utility/RegisterInfos_arm64.h
+++ b/source/Plugins/Process/Utility/RegisterInfos_arm64.h
@@ -15,8 +15,8 @@
#include "lldb/lldb-defines.h"
#include "lldb/lldb-enumerations.h"
-#include "ARM64_GCC_Registers.h"
-#include "ARM64_DWARF_Registers.h"
+#include "Utility/ARM64_GCC_Registers.h"
+#include "Utility/ARM64_DWARF_Registers.h"
#ifndef GPR_OFFSET
#error GPR_OFFSET must be defined before including this header file
diff --git a/source/Plugins/Process/Utility/RegisterInfos_i386.h b/source/Plugins/Process/Utility/RegisterInfos_i386.h
index fa152b4147ce..fc94b8b2a738 100644
--- a/source/Plugins/Process/Utility/RegisterInfos_i386.h
+++ b/source/Plugins/Process/Utility/RegisterInfos_i386.h
@@ -42,37 +42,37 @@
// 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##_i386 }, NULL, NULL }
+ eFormatHex, { kind1, kind2, kind3, kind4, lldb_##reg##_i386 }, NULL, NULL }
#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \
{ #name, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \
- eFormatHex, { kind1, kind2, kind3, kind4, fpu_##name##_i386 }, NULL, NULL }
+ eFormatHex, { kind1, kind2, kind3, kind4, lldb_##name##_i386 }, NULL, NULL }
// RegisterKind: GCC, DWARF, Generic, GDB, LLDB
#define DEFINE_FP_ST(reg, i) \
{ #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
eEncodingVector, eFormatVectorOfUInt8, \
- { gcc_st##i##_i386, dwarf_st##i##_i386, LLDB_INVALID_REGNUM, gdb_st##i##_i386, fpu_st##i##_i386 }, \
+ { gcc_st##i##_i386, dwarf_st##i##_i386, LLDB_INVALID_REGNUM, gdb_st##i##_i386, lldb_st##i##_i386 }, \
NULL, NULL }
#define DEFINE_FP_MM(reg, i) \
{ #reg#i, NULL, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
eEncodingUint, eFormatHex, \
- { gcc_mm##i##_i386, dwarf_mm##i##_i386, LLDB_INVALID_REGNUM, gdb_mm##i##_i386, fpu_mm##i##_i386 }, \
+ { gcc_mm##i##_i386, dwarf_mm##i##_i386, LLDB_INVALID_REGNUM, gdb_mm##i##_i386, lldb_mm##i##_i386 }, \
NULL, NULL }
#define DEFINE_XMM(reg, i) \
{ #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
eEncodingVector, eFormatVectorOfUInt8, \
- { gcc_##reg##i##_i386, dwarf_##reg##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##_i386, fpu_##reg##i##_i386}, \
+ { gcc_##reg##i##_i386, dwarf_##reg##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##_i386, lldb_##reg##i##_i386}, \
NULL, NULL }
// 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]), \
eEncodingVector, eFormatVectorOfUInt8, \
- { LLDB_INVALID_REGNUM, dwarf_xmm##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##h_i386, fpu_##reg##i##_i386 }, \
+ { LLDB_INVALID_REGNUM, dwarf_xmm##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##h_i386, lldb_##reg##i##_i386 }, \
NULL, NULL }
#define DEFINE_DR(reg, i) \
@@ -82,13 +82,13 @@
#define DEFINE_GPR_PSEUDO_16(reg16, reg32) \
{ #reg16, NULL, 2, GPR_OFFSET(reg32), eEncodingUint, \
- eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg16##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 }
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg16##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 }
#define DEFINE_GPR_PSEUDO_8H(reg8, reg32) \
{ #reg8, NULL, 1, GPR_OFFSET(reg32)+1, eEncodingUint, \
- eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 }
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 }
#define DEFINE_GPR_PSEUDO_8L(reg8, reg32) \
{ #reg8, NULL, 1, GPR_OFFSET(reg32), eEncodingUint, \
- eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 }
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 }
static RegisterInfo
g_register_infos_i386[] =
diff --git a/source/Plugins/Process/Utility/RegisterInfos_powerpc.h b/source/Plugins/Process/Utility/RegisterInfos_powerpc.h
new file mode 100644
index 000000000000..045426648105
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterInfos_powerpc.h
@@ -0,0 +1,144 @@
+//===-- RegisterInfos_powerpc.h ---------------------------------*- 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>
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(GPR, regname))
+#define FPR_OFFSET(regname) \
+ (offsetof(FPR, regname))
+#define GPR_SIZE(regname) \
+ (sizeof(((GPR*)NULL)->regname))
+
+#ifdef DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, lldb_kind) \
+ { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { gcc_dwarf_##reg##_powerpc, gcc_dwarf_##reg##_powerpc, lldb_kind, gdb_##reg##_powerpc, gpr_##reg##_powerpc }, NULL, NULL }
+#define DEFINE_FPR(reg, lldb_kind) \
+ { #reg, NULL, 8, FPR_OFFSET(reg), eEncodingIEEE754, \
+ eFormatFloat, { gcc_dwarf_##reg##_powerpc, gcc_dwarf_##reg##_powerpc, lldb_kind, gdb_##reg##_powerpc, fpr_##reg##_powerpc }, NULL, NULL }
+
+ // General purpose registers. GCC, DWARF, Generic, GDB
+#define POWERPC_REGS \
+ DEFINE_GPR(r0, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r1, "sp", LLDB_REGNUM_GENERIC_SP), \
+ DEFINE_GPR(r2, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r3, "arg1",LLDB_REGNUM_GENERIC_ARG1), \
+ DEFINE_GPR(r4, "arg2",LLDB_REGNUM_GENERIC_ARG2), \
+ DEFINE_GPR(r5, "arg3",LLDB_REGNUM_GENERIC_ARG3), \
+ DEFINE_GPR(r6, "arg4",LLDB_REGNUM_GENERIC_ARG4), \
+ DEFINE_GPR(r7, "arg5",LLDB_REGNUM_GENERIC_ARG5), \
+ DEFINE_GPR(r8, "arg6",LLDB_REGNUM_GENERIC_ARG6), \
+ DEFINE_GPR(r9, "arg7",LLDB_REGNUM_GENERIC_ARG7), \
+ DEFINE_GPR(r10, "arg8",LLDB_REGNUM_GENERIC_ARG8), \
+ DEFINE_GPR(r11, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r12, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r13, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r14, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r15, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r16, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r17, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r18, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r19, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r20, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r21, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r22, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r23, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r24, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r25, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r26, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r27, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r28, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r29, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r30, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r31, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(lr, "lr", LLDB_REGNUM_GENERIC_RA), \
+ DEFINE_GPR(cr, "cr", LLDB_REGNUM_GENERIC_FLAGS), \
+ DEFINE_GPR(xer, "xer", LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(ctr, "ctr", LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(pc, "pc", LLDB_REGNUM_GENERIC_PC), \
+ DEFINE_FPR(f0, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f1, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f2, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f3, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f4, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f5, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f6, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f7, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f8, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f9, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f10, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f11, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f12, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f13, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f14, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f15, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f16, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f17, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f18, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f19, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f20, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f21, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f22, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f23, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f24, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f25, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f26, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f27, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f28, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f29, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f30, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f31, LLDB_INVALID_REGNUM), \
+ { "fpscr", NULL, 8, FPR_OFFSET(fpscr), eEncodingUint, eFormatHex, { gcc_dwarf_fpscr_powerpc, gcc_dwarf_fpscr_powerpc, LLDB_INVALID_REGNUM, gdb_fpscr_powerpc, fpr_fpscr_powerpc }, NULL, NULL },
+static RegisterInfo
+g_register_infos_powerpc64[] =
+{
+#define GPR GPR64
+ POWERPC_REGS
+#undef GPR
+};
+
+static RegisterInfo
+g_register_infos_powerpc32[] =
+{
+#define GPR GPR32
+ POWERPC_REGS
+#undef GPR
+};
+
+static RegisterInfo
+g_register_infos_powerpc64_32[] =
+{
+#define GPR GPR64
+#undef GPR_SIZE
+#define GPR_SIZE(reg) (sizeof(uint32_t))
+#undef GPR_OFFSET
+#define GPR_OFFSET(regname) \
+ (offsetof(GPR, regname) + (sizeof(((GPR *)NULL)->regname) - GPR_SIZE(reg)))
+ POWERPC_REGS
+#undef GPR
+};
+
+static_assert((sizeof(g_register_infos_powerpc32) / sizeof(g_register_infos_powerpc32[0])) == k_num_registers_powerpc,
+ "g_register_infos_powerpc32 has wrong number of register infos");
+static_assert((sizeof(g_register_infos_powerpc64) / sizeof(g_register_infos_powerpc64[0])) == k_num_registers_powerpc,
+ "g_register_infos_powerpc64 has wrong number of register infos");
+static_assert(sizeof(g_register_infos_powerpc64_32) == sizeof(g_register_infos_powerpc64),
+ "g_register_infos_powerpc64_32 doesn't match size of g_register_infos_powerpc64");
+
+#undef DEFINE_FPR
+#undef DEFINE_GPR
+
+#endif // DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+
+#undef GPR_OFFSET
+
diff --git a/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
index c4dc6041ce43..c1bcd27053c6 100644
--- a/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
+++ b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
@@ -42,34 +42,34 @@
// 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##_x86_64 }, NULL, NULL }
+ eFormatHex, { kind1, kind2, kind3, kind4, lldb_##reg##_x86_64 }, NULL, NULL }
#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \
{ #name, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \
- eFormatHex, { kind1, kind2, kind3, kind4, fpu_##name##_x86_64 }, NULL, NULL }
+ eFormatHex, { kind1, kind2, kind3, kind4, lldb_##name##_x86_64 }, NULL, NULL }
#define DEFINE_FP_ST(reg, i) \
{ #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
eEncodingVector, eFormatVectorOfUInt8, \
- { gcc_dwarf_st##i##_x86_64, gcc_dwarf_st##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, fpu_st##i##_x86_64 }, \
+ { gcc_dwarf_st##i##_x86_64, gcc_dwarf_st##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, lldb_st##i##_x86_64 }, \
NULL, NULL }
#define DEFINE_FP_MM(reg, i) \
{ #reg#i, NULL, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
eEncodingUint, eFormatHex, \
- { gcc_dwarf_mm##i##_x86_64, gcc_dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, fpu_mm##i##_x86_64 }, \
+ { gcc_dwarf_mm##i##_x86_64, gcc_dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, lldb_mm##i##_x86_64 }, \
NULL, NULL }
#define DEFINE_XMM(reg, i) \
{ #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
eEncodingVector, eFormatVectorOfUInt8, \
- { gcc_dwarf_##reg##i##_x86_64, gcc_dwarf_##reg##i##_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##_x86_64, fpu_##reg##i##_x86_64}, \
+ { gcc_dwarf_##reg##i##_x86_64, gcc_dwarf_##reg##i##_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##_x86_64, lldb_##reg##i##_x86_64}, \
NULL, NULL }
#define DEFINE_YMM(reg, i) \
{ #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[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, fpu_##reg##i##_x86_64 }, \
+ { 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 }
#define DEFINE_DR(reg, i) \
@@ -79,16 +79,16 @@
#define DEFINE_GPR_PSEUDO_32(reg32, reg64) \
{ #reg32, NULL, 4, GPR_OFFSET(reg64), eEncodingUint, \
- eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg32##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg32##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
#define DEFINE_GPR_PSEUDO_16(reg16, reg64) \
{ #reg16, NULL, 2, GPR_OFFSET(reg64), eEncodingUint, \
- eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg16##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg16##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
#define DEFINE_GPR_PSEUDO_8H(reg8, reg64) \
{ #reg8, NULL, 1, GPR_OFFSET(reg64)+1, eEncodingUint, \
- eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
#define DEFINE_GPR_PSEUDO_8L(reg8, reg64) \
{ #reg8, NULL, 1, GPR_OFFSET(reg64), eEncodingUint, \
- eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
static RegisterInfo
g_register_infos_x86_64[] =
@@ -273,37 +273,37 @@ static_assert((sizeof(g_register_infos_x86_64) / sizeof(g_register_infos_x86_64[
#define UPDATE_GPR_INFO(reg, reg64) \
do { \
- g_register_infos[gpr_##reg##_i386].byte_offset = GPR_OFFSET(reg64); \
+ g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64); \
} while(false);
#define UPDATE_GPR_INFO_8H(reg, reg64) \
do { \
- g_register_infos[gpr_##reg##_i386].byte_offset = GPR_OFFSET(reg64) + 1; \
+ g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64) + 1; \
} while(false);
#define UPDATE_FPR_INFO(reg, reg64) \
do { \
- g_register_infos[fpu_##reg##_i386].byte_offset = FPR_OFFSET(reg64); \
+ g_register_infos[lldb_##reg##_i386].byte_offset = FPR_OFFSET(reg64); \
} while(false);
#define UPDATE_FP_INFO(reg, i) \
do { \
- g_register_infos[fpu_##reg##i##_i386].byte_offset = FPR_OFFSET(stmm[i]); \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(stmm[i]); \
} while(false);
#define UPDATE_XMM_INFO(reg, i) \
do { \
- g_register_infos[fpu_##reg##i##_i386].byte_offset = FPR_OFFSET(reg[i]); \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(reg[i]); \
} while(false);
#define UPDATE_YMM_INFO(reg, i) \
do { \
- g_register_infos[fpu_##reg##i##_i386].byte_offset = YMM_OFFSET(reg[i]); \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = YMM_OFFSET(reg[i]); \
} while(false);
#define UPDATE_DR_INFO(reg_index) \
do { \
- g_register_infos[dr##reg_index##_i386].byte_offset = DR_OFFSET(reg_index); \
+ g_register_infos[lldb_dr##reg_index##_i386].byte_offset = DR_OFFSET(reg_index); \
} while(false);
// Update the register offsets
diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp
index 0e3e559aef5c..a69b38b6c93e 100644
--- a/source/Plugins/Process/Utility/StopInfoMachException.cpp
+++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -423,9 +423,11 @@ StopInfoMachException::CreateStopReasonWithMachException
wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
}
- // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS
- if (thread.GetTemporaryResumeState() == eStateStepping)
- return StopInfo::CreateStopReasonToTrace(thread);
+ else
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
}
else if (exc_code == 1) // EXC_ARM_BREAKPOINT
{
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp
index 37fd4f489552..fc592e60d86d 100644
--- a/source/Plugins/Process/Utility/UnwindLLDB.cpp
+++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp
@@ -172,8 +172,9 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)
if (!reg_ctx_sp->IsValid())
{
- // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
- // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
+ // We failed to get a valid RegisterContext.
+ // See if the regctx below this on the stack has a fallback unwind plan it can use.
+ // Subsequent calls to TryFallbackUnwindPlan() will return false.
if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
{
return AddOneMoreFrame (abi);
@@ -207,18 +208,35 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)
// these.
if (reg_ctx_sp->IsTrapHandlerFrame() == false)
{
- // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
- // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
- if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ // See if we can find a fallback unwind plan for THIS frame. It may be
+ // that the UnwindPlan we're using for THIS frame was bad and gave us a
+ // bad CFA.
+ // If that's not it, then see if we can change the UnwindPlan for the frame
+ // below us ("NEXT") -- see if using that other UnwindPlan gets us a better
+ // unwind state.
+ if (reg_ctx_sp->TryFallbackUnwindPlan() == false
+ || reg_ctx_sp->GetCFA (cursor_sp->cfa) == false
+ || abi->CallFrameAddressIsValid(cursor_sp->cfa) == false)
{
- return AddOneMoreFrame (abi);
+ if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ {
+ return AddOneMoreFrame (abi);
+ }
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
}
- if (log)
+ else
{
- log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk",
- cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ if (log)
+ {
+ log->Printf("%*sFrame %d had a bad CFA value but we switched the UnwindPlan being used and got one that looks more realistic.",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
}
- goto unwind_done;
}
}
if (!reg_ctx_sp->ReadPC (cursor_sp->start_pc))
@@ -366,6 +384,14 @@ UnwindLLDB::SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
UnwindLLDB::RegisterSearchResult result;
result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister (lldb_regnum, regloc);
+ // We descended down to the live register context aka stack frame 0 and are reading the value
+ // out of a live register.
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound
+ && regloc.type == UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext)
+ {
+ return true;
+ }
+
// If we have unwind instructions saying that register N is saved in register M in the middle of
// the stack (and N can equal M here, meaning the register was not used in this function), then
// change the register number we're looking for to M and keep looking for a concrete location
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.h b/source/Plugins/Process/Utility/UnwindLLDB.h
index eb5400389df3..35d85e2e3d26 100644
--- a/source/Plugins/Process/Utility/UnwindLLDB.h
+++ b/source/Plugins/Process/Utility/UnwindLLDB.h
@@ -48,7 +48,8 @@ protected:
eRegisterSavedAtMemoryLocation, // register is saved at a specific word of target mem (target_memory_location)
eRegisterInRegister, // register is available in a (possible other) register (register_number)
eRegisterSavedAtHostMemoryLocation, // register is saved at a word in lldb's address space
- eRegisterValueInferred // register val was computed (and is in inferred_value)
+ eRegisterValueInferred, // register val was computed (and is in inferred_value)
+ eRegisterInLiveRegisterContext // register value is in a live (stack frame #0) register
};
int type;
union
diff --git a/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/source/Plugins/Process/Utility/lldb-x86-register-enums.h
index c4706d567b70..99fca3005820 100644
--- a/source/Plugins/Process/Utility/lldb-x86-register-enums.h
+++ b/source/Plugins/Process/Utility/lldb-x86-register-enums.h
@@ -12,6 +12,7 @@
namespace lldb_private
{
+ // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
//---------------------------------------------------------------------------
// Internal codes for all i386 registers.
@@ -19,100 +20,100 @@ namespace lldb_private
enum
{
k_first_gpr_i386,
- gpr_eax_i386 = k_first_gpr_i386,
- gpr_ebx_i386,
- gpr_ecx_i386,
- gpr_edx_i386,
- gpr_edi_i386,
- gpr_esi_i386,
- gpr_ebp_i386,
- gpr_esp_i386,
- gpr_eip_i386,
- gpr_eflags_i386,
- gpr_cs_i386,
- gpr_fs_i386,
- gpr_gs_i386,
- gpr_ss_i386,
- gpr_ds_i386,
- gpr_es_i386,
+ lldb_eax_i386 = k_first_gpr_i386,
+ lldb_ebx_i386,
+ lldb_ecx_i386,
+ lldb_edx_i386,
+ lldb_edi_i386,
+ lldb_esi_i386,
+ lldb_ebp_i386,
+ lldb_esp_i386,
+ lldb_eip_i386,
+ lldb_eflags_i386,
+ lldb_cs_i386,
+ lldb_fs_i386,
+ lldb_gs_i386,
+ lldb_ss_i386,
+ lldb_ds_i386,
+ lldb_es_i386,
k_first_alias_i386,
- gpr_ax_i386 = k_first_alias_i386,
- gpr_bx_i386,
- gpr_cx_i386,
- gpr_dx_i386,
- gpr_di_i386,
- gpr_si_i386,
- gpr_bp_i386,
- gpr_sp_i386,
- gpr_ah_i386,
- gpr_bh_i386,
- gpr_ch_i386,
- gpr_dh_i386,
- gpr_al_i386,
- gpr_bl_i386,
- gpr_cl_i386,
- gpr_dl_i386,
- k_last_alias_i386 = gpr_dl_i386,
+ lldb_ax_i386 = k_first_alias_i386,
+ lldb_bx_i386,
+ lldb_cx_i386,
+ lldb_dx_i386,
+ lldb_di_i386,
+ lldb_si_i386,
+ lldb_bp_i386,
+ lldb_sp_i386,
+ lldb_ah_i386,
+ lldb_bh_i386,
+ lldb_ch_i386,
+ lldb_dh_i386,
+ lldb_al_i386,
+ lldb_bl_i386,
+ lldb_cl_i386,
+ lldb_dl_i386,
+ k_last_alias_i386 = lldb_dl_i386,
k_last_gpr_i386 = k_last_alias_i386,
k_first_fpr_i386,
- fpu_fctrl_i386 = k_first_fpr_i386,
- fpu_fstat_i386,
- fpu_ftag_i386,
- fpu_fop_i386,
- fpu_fiseg_i386,
- fpu_fioff_i386,
- fpu_foseg_i386,
- fpu_fooff_i386,
- fpu_mxcsr_i386,
- fpu_mxcsrmask_i386,
- fpu_st0_i386,
- fpu_st1_i386,
- fpu_st2_i386,
- fpu_st3_i386,
- fpu_st4_i386,
- fpu_st5_i386,
- fpu_st6_i386,
- fpu_st7_i386,
- fpu_mm0_i386,
- fpu_mm1_i386,
- fpu_mm2_i386,
- fpu_mm3_i386,
- fpu_mm4_i386,
- fpu_mm5_i386,
- fpu_mm6_i386,
- fpu_mm7_i386,
- fpu_xmm0_i386,
- fpu_xmm1_i386,
- fpu_xmm2_i386,
- fpu_xmm3_i386,
- fpu_xmm4_i386,
- fpu_xmm5_i386,
- fpu_xmm6_i386,
- fpu_xmm7_i386,
- k_last_fpr_i386 = fpu_xmm7_i386,
+ lldb_fctrl_i386 = k_first_fpr_i386,
+ lldb_fstat_i386,
+ lldb_ftag_i386,
+ lldb_fop_i386,
+ lldb_fiseg_i386,
+ lldb_fioff_i386,
+ lldb_foseg_i386,
+ lldb_fooff_i386,
+ lldb_mxcsr_i386,
+ lldb_mxcsrmask_i386,
+ lldb_st0_i386,
+ lldb_st1_i386,
+ lldb_st2_i386,
+ lldb_st3_i386,
+ lldb_st4_i386,
+ lldb_st5_i386,
+ lldb_st6_i386,
+ lldb_st7_i386,
+ lldb_mm0_i386,
+ lldb_mm1_i386,
+ lldb_mm2_i386,
+ lldb_mm3_i386,
+ lldb_mm4_i386,
+ lldb_mm5_i386,
+ lldb_mm6_i386,
+ lldb_mm7_i386,
+ lldb_xmm0_i386,
+ lldb_xmm1_i386,
+ lldb_xmm2_i386,
+ lldb_xmm3_i386,
+ lldb_xmm4_i386,
+ lldb_xmm5_i386,
+ lldb_xmm6_i386,
+ lldb_xmm7_i386,
+ k_last_fpr_i386 = lldb_xmm7_i386,
k_first_avx_i386,
- fpu_ymm0_i386 = k_first_avx_i386,
- fpu_ymm1_i386,
- fpu_ymm2_i386,
- fpu_ymm3_i386,
- fpu_ymm4_i386,
- fpu_ymm5_i386,
- fpu_ymm6_i386,
- fpu_ymm7_i386,
- k_last_avx_i386 = fpu_ymm7_i386,
+ lldb_ymm0_i386 = k_first_avx_i386,
+ lldb_ymm1_i386,
+ lldb_ymm2_i386,
+ lldb_ymm3_i386,
+ lldb_ymm4_i386,
+ lldb_ymm5_i386,
+ lldb_ymm6_i386,
+ lldb_ymm7_i386,
+ k_last_avx_i386 = lldb_ymm7_i386,
- dr0_i386,
- dr1_i386,
- dr2_i386,
- dr3_i386,
- dr4_i386,
- dr5_i386,
- dr6_i386,
- dr7_i386,
+ lldb_dr0_i386,
+ lldb_dr1_i386,
+ lldb_dr2_i386,
+ lldb_dr3_i386,
+ lldb_dr4_i386,
+ lldb_dr5_i386,
+ lldb_dr6_i386,
+ lldb_dr7_i386,
k_num_registers_i386,
k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1,
@@ -126,160 +127,160 @@ namespace lldb_private
enum
{
k_first_gpr_x86_64,
- gpr_rax_x86_64 = k_first_gpr_x86_64,
- gpr_rbx_x86_64,
- gpr_rcx_x86_64,
- gpr_rdx_x86_64,
- gpr_rdi_x86_64,
- gpr_rsi_x86_64,
- gpr_rbp_x86_64,
- gpr_rsp_x86_64,
- gpr_r8_x86_64,
- gpr_r9_x86_64,
- gpr_r10_x86_64,
- gpr_r11_x86_64,
- gpr_r12_x86_64,
- gpr_r13_x86_64,
- gpr_r14_x86_64,
- gpr_r15_x86_64,
- gpr_rip_x86_64,
- gpr_rflags_x86_64,
- gpr_cs_x86_64,
- gpr_fs_x86_64,
- gpr_gs_x86_64,
- gpr_ss_x86_64,
- gpr_ds_x86_64,
- gpr_es_x86_64,
+ lldb_rax_x86_64 = k_first_gpr_x86_64,
+ lldb_rbx_x86_64,
+ lldb_rcx_x86_64,
+ lldb_rdx_x86_64,
+ lldb_rdi_x86_64,
+ lldb_rsi_x86_64,
+ lldb_rbp_x86_64,
+ lldb_rsp_x86_64,
+ lldb_r8_x86_64,
+ lldb_r9_x86_64,
+ lldb_r10_x86_64,
+ lldb_r11_x86_64,
+ lldb_r12_x86_64,
+ lldb_r13_x86_64,
+ lldb_r14_x86_64,
+ lldb_r15_x86_64,
+ lldb_rip_x86_64,
+ lldb_rflags_x86_64,
+ lldb_cs_x86_64,
+ lldb_fs_x86_64,
+ lldb_gs_x86_64,
+ lldb_ss_x86_64,
+ lldb_ds_x86_64,
+ lldb_es_x86_64,
k_first_alias_x86_64,
- gpr_eax_x86_64 = k_first_alias_x86_64,
- gpr_ebx_x86_64,
- gpr_ecx_x86_64,
- gpr_edx_x86_64,
- gpr_edi_x86_64,
- gpr_esi_x86_64,
- gpr_ebp_x86_64,
- gpr_esp_x86_64,
- gpr_r8d_x86_64, // Low 32 bits of r8
- gpr_r9d_x86_64, // Low 32 bits of r9
- gpr_r10d_x86_64, // Low 32 bits of r10
- gpr_r11d_x86_64, // Low 32 bits of r11
- gpr_r12d_x86_64, // Low 32 bits of r12
- gpr_r13d_x86_64, // Low 32 bits of r13
- gpr_r14d_x86_64, // Low 32 bits of r14
- gpr_r15d_x86_64, // Low 32 bits of r15
- gpr_ax_x86_64,
- gpr_bx_x86_64,
- gpr_cx_x86_64,
- gpr_dx_x86_64,
- gpr_di_x86_64,
- gpr_si_x86_64,
- gpr_bp_x86_64,
- gpr_sp_x86_64,
- gpr_r8w_x86_64, // Low 16 bits of r8
- gpr_r9w_x86_64, // Low 16 bits of r9
- gpr_r10w_x86_64, // Low 16 bits of r10
- gpr_r11w_x86_64, // Low 16 bits of r11
- gpr_r12w_x86_64, // Low 16 bits of r12
- gpr_r13w_x86_64, // Low 16 bits of r13
- gpr_r14w_x86_64, // Low 16 bits of r14
- gpr_r15w_x86_64, // Low 16 bits of r15
- gpr_ah_x86_64,
- gpr_bh_x86_64,
- gpr_ch_x86_64,
- gpr_dh_x86_64,
- gpr_al_x86_64,
- gpr_bl_x86_64,
- gpr_cl_x86_64,
- gpr_dl_x86_64,
- gpr_dil_x86_64,
- gpr_sil_x86_64,
- gpr_bpl_x86_64,
- gpr_spl_x86_64,
- gpr_r8l_x86_64, // Low 8 bits of r8
- gpr_r9l_x86_64, // Low 8 bits of r9
- gpr_r10l_x86_64, // Low 8 bits of r10
- gpr_r11l_x86_64, // Low 8 bits of r11
- gpr_r12l_x86_64, // Low 8 bits of r12
- gpr_r13l_x86_64, // Low 8 bits of r13
- gpr_r14l_x86_64, // Low 8 bits of r14
- gpr_r15l_x86_64, // Low 8 bits of r15
- k_last_alias_x86_64 = gpr_r15l_x86_64,
+ lldb_eax_x86_64 = k_first_alias_x86_64,
+ lldb_ebx_x86_64,
+ lldb_ecx_x86_64,
+ lldb_edx_x86_64,
+ lldb_edi_x86_64,
+ lldb_esi_x86_64,
+ lldb_ebp_x86_64,
+ lldb_esp_x86_64,
+ lldb_r8d_x86_64, // Low 32 bits of r8
+ lldb_r9d_x86_64, // Low 32 bits of r9
+ lldb_r10d_x86_64, // Low 32 bits of r10
+ lldb_r11d_x86_64, // Low 32 bits of r11
+ lldb_r12d_x86_64, // Low 32 bits of r12
+ lldb_r13d_x86_64, // Low 32 bits of r13
+ lldb_r14d_x86_64, // Low 32 bits of r14
+ lldb_r15d_x86_64, // Low 32 bits of r15
+ lldb_ax_x86_64,
+ lldb_bx_x86_64,
+ lldb_cx_x86_64,
+ lldb_dx_x86_64,
+ lldb_di_x86_64,
+ lldb_si_x86_64,
+ lldb_bp_x86_64,
+ lldb_sp_x86_64,
+ lldb_r8w_x86_64, // Low 16 bits of r8
+ lldb_r9w_x86_64, // Low 16 bits of r9
+ lldb_r10w_x86_64, // Low 16 bits of r10
+ lldb_r11w_x86_64, // Low 16 bits of r11
+ lldb_r12w_x86_64, // Low 16 bits of r12
+ lldb_r13w_x86_64, // Low 16 bits of r13
+ lldb_r14w_x86_64, // Low 16 bits of r14
+ lldb_r15w_x86_64, // Low 16 bits of r15
+ lldb_ah_x86_64,
+ lldb_bh_x86_64,
+ lldb_ch_x86_64,
+ lldb_dh_x86_64,
+ lldb_al_x86_64,
+ lldb_bl_x86_64,
+ lldb_cl_x86_64,
+ lldb_dl_x86_64,
+ lldb_dil_x86_64,
+ lldb_sil_x86_64,
+ lldb_bpl_x86_64,
+ lldb_spl_x86_64,
+ lldb_r8l_x86_64, // Low 8 bits of r8
+ lldb_r9l_x86_64, // Low 8 bits of r9
+ lldb_r10l_x86_64, // Low 8 bits of r10
+ lldb_r11l_x86_64, // Low 8 bits of r11
+ lldb_r12l_x86_64, // Low 8 bits of r12
+ lldb_r13l_x86_64, // Low 8 bits of r13
+ lldb_r14l_x86_64, // Low 8 bits of r14
+ lldb_r15l_x86_64, // Low 8 bits of r15
+ k_last_alias_x86_64 = lldb_r15l_x86_64,
k_last_gpr_x86_64 = k_last_alias_x86_64,
k_first_fpr_x86_64,
- fpu_fctrl_x86_64 = k_first_fpr_x86_64,
- fpu_fstat_x86_64,
- fpu_ftag_x86_64,
- fpu_fop_x86_64,
- fpu_fiseg_x86_64,
- fpu_fioff_x86_64,
- fpu_foseg_x86_64,
- fpu_fooff_x86_64,
- fpu_mxcsr_x86_64,
- fpu_mxcsrmask_x86_64,
- fpu_st0_x86_64,
- fpu_st1_x86_64,
- fpu_st2_x86_64,
- fpu_st3_x86_64,
- fpu_st4_x86_64,
- fpu_st5_x86_64,
- fpu_st6_x86_64,
- fpu_st7_x86_64,
- fpu_mm0_x86_64,
- fpu_mm1_x86_64,
- fpu_mm2_x86_64,
- fpu_mm3_x86_64,
- fpu_mm4_x86_64,
- fpu_mm5_x86_64,
- fpu_mm6_x86_64,
- fpu_mm7_x86_64,
- fpu_xmm0_x86_64,
- fpu_xmm1_x86_64,
- fpu_xmm2_x86_64,
- fpu_xmm3_x86_64,
- fpu_xmm4_x86_64,
- fpu_xmm5_x86_64,
- fpu_xmm6_x86_64,
- fpu_xmm7_x86_64,
- fpu_xmm8_x86_64,
- fpu_xmm9_x86_64,
- fpu_xmm10_x86_64,
- fpu_xmm11_x86_64,
- fpu_xmm12_x86_64,
- fpu_xmm13_x86_64,
- fpu_xmm14_x86_64,
- fpu_xmm15_x86_64,
- k_last_fpr_x86_64 = fpu_xmm15_x86_64,
+ lldb_fctrl_x86_64 = k_first_fpr_x86_64,
+ lldb_fstat_x86_64,
+ lldb_ftag_x86_64,
+ lldb_fop_x86_64,
+ lldb_fiseg_x86_64,
+ lldb_fioff_x86_64,
+ lldb_foseg_x86_64,
+ lldb_fooff_x86_64,
+ lldb_mxcsr_x86_64,
+ lldb_mxcsrmask_x86_64,
+ lldb_st0_x86_64,
+ lldb_st1_x86_64,
+ lldb_st2_x86_64,
+ lldb_st3_x86_64,
+ lldb_st4_x86_64,
+ lldb_st5_x86_64,
+ lldb_st6_x86_64,
+ lldb_st7_x86_64,
+ lldb_mm0_x86_64,
+ lldb_mm1_x86_64,
+ lldb_mm2_x86_64,
+ lldb_mm3_x86_64,
+ lldb_mm4_x86_64,
+ lldb_mm5_x86_64,
+ lldb_mm6_x86_64,
+ lldb_mm7_x86_64,
+ lldb_xmm0_x86_64,
+ lldb_xmm1_x86_64,
+ lldb_xmm2_x86_64,
+ lldb_xmm3_x86_64,
+ lldb_xmm4_x86_64,
+ lldb_xmm5_x86_64,
+ lldb_xmm6_x86_64,
+ lldb_xmm7_x86_64,
+ lldb_xmm8_x86_64,
+ lldb_xmm9_x86_64,
+ lldb_xmm10_x86_64,
+ lldb_xmm11_x86_64,
+ lldb_xmm12_x86_64,
+ lldb_xmm13_x86_64,
+ lldb_xmm14_x86_64,
+ lldb_xmm15_x86_64,
+ k_last_fpr_x86_64 = lldb_xmm15_x86_64,
k_first_avx_x86_64,
- fpu_ymm0_x86_64 = k_first_avx_x86_64,
- fpu_ymm1_x86_64,
- fpu_ymm2_x86_64,
- fpu_ymm3_x86_64,
- fpu_ymm4_x86_64,
- fpu_ymm5_x86_64,
- fpu_ymm6_x86_64,
- fpu_ymm7_x86_64,
- fpu_ymm8_x86_64,
- fpu_ymm9_x86_64,
- fpu_ymm10_x86_64,
- fpu_ymm11_x86_64,
- fpu_ymm12_x86_64,
- fpu_ymm13_x86_64,
- fpu_ymm14_x86_64,
- fpu_ymm15_x86_64,
- k_last_avx_x86_64 = fpu_ymm15_x86_64,
+ lldb_ymm0_x86_64 = k_first_avx_x86_64,
+ lldb_ymm1_x86_64,
+ lldb_ymm2_x86_64,
+ lldb_ymm3_x86_64,
+ lldb_ymm4_x86_64,
+ lldb_ymm5_x86_64,
+ lldb_ymm6_x86_64,
+ lldb_ymm7_x86_64,
+ lldb_ymm8_x86_64,
+ lldb_ymm9_x86_64,
+ lldb_ymm10_x86_64,
+ lldb_ymm11_x86_64,
+ lldb_ymm12_x86_64,
+ lldb_ymm13_x86_64,
+ lldb_ymm14_x86_64,
+ lldb_ymm15_x86_64,
+ k_last_avx_x86_64 = lldb_ymm15_x86_64,
- dr0_x86_64,
- dr1_x86_64,
- dr2_x86_64,
- dr3_x86_64,
- dr4_x86_64,
- dr5_x86_64,
- dr6_x86_64,
- dr7_x86_64,
+ lldb_dr0_x86_64,
+ lldb_dr1_x86_64,
+ lldb_dr2_x86_64,
+ lldb_dr3_x86_64,
+ lldb_dr4_x86_64,
+ lldb_dr5_x86_64,
+ lldb_dr6_x86_64,
+ lldb_dr7_x86_64,
k_num_registers_x86_64,
k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1,
diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 566816783c7e..fb39d7318a5a 100644
--- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -405,14 +405,18 @@ enum {
NT_AUXV
};
+namespace FREEBSD {
+
enum {
- NT_FREEBSD_PRSTATUS = 1,
- NT_FREEBSD_FPREGSET,
- NT_FREEBSD_PRPSINFO,
- NT_FREEBSD_THRMISC = 7,
- NT_FREEBSD_PROCSTAT_AUXV = 16
+ NT_PRSTATUS = 1,
+ NT_FPREGSET,
+ NT_PRPSINFO,
+ NT_THRMISC = 7,
+ NT_PROCSTAT_AUXV = 16
};
+}
+
// Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details.
static void
ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data,
@@ -420,6 +424,7 @@ ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data,
{
lldb::offset_t offset = 0;
bool lp64 = (arch.GetMachine() == llvm::Triple::mips64 ||
+ arch.GetMachine() == llvm::Triple::ppc64 ||
arch.GetMachine() == llvm::Triple::x86_64);
int pr_version = data.GetU32(&offset);
@@ -516,20 +521,20 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *
m_os = llvm::Triple::FreeBSD;
switch (note.n_type)
{
- case NT_FREEBSD_PRSTATUS:
+ case FREEBSD::NT_PRSTATUS:
have_prstatus = true;
ParseFreeBSDPrStatus(*thread_data, note_data, arch);
break;
- case NT_FREEBSD_FPREGSET:
+ case FREEBSD::NT_FPREGSET:
thread_data->fpregset = note_data;
break;
- case NT_FREEBSD_PRPSINFO:
+ case FREEBSD::NT_PRPSINFO:
have_prpsinfo = true;
break;
- case NT_FREEBSD_THRMISC:
+ case FREEBSD::NT_THRMISC:
ParseFreeBSDThrMisc(*thread_data, note_data);
break;
- case NT_FREEBSD_PROCSTAT_AUXV:
+ case FREEBSD::NT_PROCSTAT_AUXV:
// FIXME: FreeBSD sticks an int at the beginning of the note
m_auxv = DataExtractor(segment_data, note_start + 4, note_size - 4);
break;
diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.h b/source/Plugins/Process/elf-core/ProcessElfCore.h
index 2fc2e4ee7949..7988bee5ae53 100644
--- a/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -68,52 +68,52 @@ public:
//------------------------------------------------------------------
virtual bool
CanDebug (lldb_private::Target &target,
- bool plugin_specified_by_name);
+ bool plugin_specified_by_name) override;
//------------------------------------------------------------------
// Creating a new process, or attaching to an existing one
//------------------------------------------------------------------
virtual lldb_private::Error
- DoLoadCore ();
+ DoLoadCore () override;
virtual lldb_private::DynamicLoader *
- GetDynamicLoader ();
+ GetDynamicLoader () override;
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
virtual lldb_private::ConstString
- GetPluginName();
+ GetPluginName() override;
virtual uint32_t
- GetPluginVersion();
+ GetPluginVersion() override;
//------------------------------------------------------------------
// Process Control
//------------------------------------------------------------------
virtual lldb_private::Error
- DoDestroy ();
+ DoDestroy () override;
virtual void
- RefreshStateAfterStop();
+ RefreshStateAfterStop() override;
//------------------------------------------------------------------
// Process Queries
//------------------------------------------------------------------
virtual bool
- IsAlive ();
+ IsAlive () override;
//------------------------------------------------------------------
// Process Memory
//------------------------------------------------------------------
virtual size_t
- ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+ 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);
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
virtual lldb::addr_t
- GetImageInfoAddress ();
+ GetImageInfoAddress () override;
lldb_private::ArchSpec
GetArchitecture();
@@ -128,7 +128,7 @@ protected:
virtual bool
UpdateThreadList (lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list);
+ lldb_private::ThreadList &new_thread_list) override;
private:
//------------------------------------------------------------------
diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
index fbf397b933cc..f0750a0cee18 100644
--- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
+++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
@@ -10,7 +10,7 @@
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
-#include "RegisterContextPOSIX.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX.h"
#include "RegisterContextPOSIXCore_mips64.h"
using namespace lldb_private;
diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp
new file mode 100644
index 000000000000..15b1b44182d7
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp
@@ -0,0 +1,109 @@
+//===-- RegisterContextCorePOSIX_powerpc.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 "RegisterContextPOSIX.h"
+#include "RegisterContextPOSIXCore_powerpc.h"
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_powerpc::RegisterContextCorePOSIX_powerpc(Thread &thread,
+ RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset,
+ const DataExtractor &fpregset)
+ : RegisterContextPOSIX_powerpc(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());
+ m_fpr_buffer.reset(new DataBufferHeap(fpregset.GetDataStart(), fpregset.GetByteSize()));
+ m_fpr.SetData(m_fpr_buffer);
+ m_fpr.SetByteOrder(fpregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_powerpc::~RegisterContextCorePOSIX_powerpc()
+{
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::ReadGPR()
+{
+ return true;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::ReadFPR()
+{
+ return true;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::WriteGPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::WriteFPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ lldb::offset_t offset = reg_info->byte_offset;
+ if (reg_info->name[0] == 'f') {
+ uint64_t v = m_fpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size)
+ {
+ value = v;
+ return true;
+ }
+ } else {
+ uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size)
+ {
+ if (reg_info->byte_size < sizeof(v))
+ value = (uint32_t)v;
+ else
+ value = v;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::HardwareSingleStep(bool enable)
+{
+ return false;
+}
diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h
new file mode 100644
index 000000000000..e6575581b360
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h
@@ -0,0 +1,62 @@
+//===-- RegisterContextCorePOSIX_powerpc.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_powerpc_H_
+#define liblldb_RegisterContextCorePOSIX_powerpc_H_
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
+
+class RegisterContextCorePOSIX_powerpc :
+ public RegisterContextPOSIX_powerpc
+{
+public:
+ RegisterContextCorePOSIX_powerpc (lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ const lldb_private::DataExtractor &fpregset);
+
+ ~RegisterContextCorePOSIX_powerpc();
+
+ 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::DataBufferSP m_fpr_buffer;
+ lldb_private::DataExtractor m_gpr;
+ lldb_private::DataExtractor m_fpr;
+};
+
+#endif // #ifndef liblldb_RegisterContextCorePOSIX_powerpc_H_
diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp
index 3e09c7bc2032..412c7ade8295 100644
--- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp
+++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp
@@ -10,7 +10,7 @@
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
-#include "RegisterContextPOSIX.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX.h"
#include "RegisterContextPOSIXCore_x86_64.h"
using namespace lldb_private;
diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp
index d9f6cc04a343..d62bcfcff600 100644
--- a/source/Plugins/Process/elf-core/ThreadElfCore.cpp
+++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp
@@ -16,11 +16,13 @@
#include "ThreadElfCore.h"
#include "ProcessElfCore.h"
-#include "RegisterContextLinux_x86_64.h"
-#include "RegisterContextFreeBSD_i386.h"
-#include "RegisterContextFreeBSD_mips64.h"
-#include "RegisterContextFreeBSD_x86_64.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.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_mips64.h"
+#include "RegisterContextPOSIXCore_powerpc.h"
#include "RegisterContextPOSIXCore_x86_64.h"
using namespace lldb;
@@ -94,6 +96,12 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
{
switch (arch.GetMachine())
{
+ case llvm::Triple::ppc:
+ reg_interface = new RegisterContextFreeBSD_powerpc32(arch);
+ break;
+ case llvm::Triple::ppc64:
+ reg_interface = new RegisterContextFreeBSD_powerpc64(arch);
+ break;
case llvm::Triple::mips64:
reg_interface = new RegisterContextFreeBSD_mips64(arch);
break;
@@ -138,6 +146,10 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
case llvm::Triple::mips64:
m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data));
break;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_powerpc (*this, reg_interface, m_gpregset_data, m_fpregset_data));
+ break;
case llvm::Triple::x86:
case llvm::Triple::x86_64:
m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, reg_interface, m_gpregset_data, m_fpregset_data));
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 1f4dd93976ec..919fa5405117 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -17,15 +17,16 @@
// C++ Includes
// Other libraries and framework includes
-#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/Pipe.h"
#include "lldb/Host/Socket.h"
+#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Host/TimeValue.h"
#include "lldb/Target/Process.h"
@@ -153,7 +154,6 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name,
m_history (512),
m_send_acks (true),
m_is_platform (is_platform),
- m_listen_thread (LLDB_INVALID_HOST_THREAD),
m_listen_url ()
{
}
@@ -227,9 +227,23 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
ConnectionStatus status = eConnectionStatusSuccess;
- size_t bytes_written = Write (packet.GetData(), packet.GetSize(), status, NULL);
+ const char *packet_data = packet.GetData();
+ const size_t packet_length = packet.GetSize();
+ size_t bytes_written = Write (packet_data, packet_length, status, NULL);
if (log)
{
+ size_t binary_start_offset = 0;
+ if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) == 0)
+ {
+ const char *first_comma = strchr(packet_data, ',');
+ if (first_comma)
+ {
+ const char *second_comma = strchr(first_comma + 1, ',');
+ if (second_comma)
+ binary_start_offset = second_comma - packet_data + 1;
+ }
+ }
+
// If logging was just enabled and we have history, then dump out what
// we have to the log so we get the historical context. The Dump() call that
// logs all of the packet will set a boolean so that we don't dump this more
@@ -237,13 +251,27 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le
if (!m_history.DidDumpToLog ())
m_history.Dump (log);
- log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)packet.GetSize(), packet.GetData());
+ if (binary_start_offset)
+ {
+ StreamString strm;
+ // Print non binary data header
+ 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)
+ strm.Printf("\\x%2.2x", *p);
+ // Print the checksum
+ strm.Printf("%*s", (int)3, p);
+ log->PutCString(strm.GetString().c_str());
+ }
+ else
+ log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)packet_length, packet_data);
}
- m_history.AddPacket (packet.GetString(), packet.GetSize(), History::ePacketTypeSend, bytes_written);
+ m_history.AddPacket (packet.GetString(), packet_length, History::ePacketTypeSend, bytes_written);
- if (bytes_written == packet.GetSize())
+ if (bytes_written == packet_length)
{
if (GetSendAcks ())
return GetAck ();
@@ -253,7 +281,7 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le
else
{
if (log)
- log->Printf ("error: failed to send packet: %.*s", (int)packet.GetSize(), packet.GetData());
+ log->Printf ("error: failed to send packet: %.*s", (int)packet_length, packet_data);
}
}
return PacketResult::ErrorSendFailed;
@@ -447,8 +475,8 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
}
if (log)
log->Printf ("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'",
- __FUNCTION__, idx, idx, m_bytes.c_str());
- m_bytes.erase(0, idx);
+ __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str());
+ m_bytes.erase(0, idx - 1);
}
break;
}
@@ -606,7 +634,7 @@ Error
GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port)
{
Error error;
- if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread))
+ if (m_listen_thread.IsJoinable())
{
error.SetErrorString("listen thread already running");
}
@@ -619,7 +647,7 @@ GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port)
snprintf(listen_url, sizeof(listen_url), "listen://%i", port);
m_listen_url = listen_url;
SetConnection(new ConnectionFileDescriptor());
- m_listen_thread = Host::ThreadCreate (listen_url, GDBRemoteCommunication::ListenThread, this, &error);
+ m_listen_thread = ThreadLauncher::LaunchThread(listen_url, GDBRemoteCommunication::ListenThread, this, &error);
}
return error;
}
@@ -627,11 +655,8 @@ GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port)
bool
GDBRemoteCommunication::JoinListenThread ()
{
- if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread))
- {
- Host::ThreadJoin(m_listen_thread, NULL, NULL);
- m_listen_thread = LLDB_INVALID_HOST_THREAD;
- }
+ if (m_listen_thread.IsJoinable())
+ m_listen_thread.Join(nullptr);
return true;
}
@@ -738,6 +763,7 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
char named_pipe_path[PATH_MAX];
named_pipe_path[0] = '\0';
+ Pipe port_named_pipe;
bool listen = false;
if (host_and_port[0])
@@ -763,15 +789,11 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
if (::mktemp (named_pipe_path))
{
-#if defined(_WIN32)
- if ( false )
-#else
- if (::mkfifo(named_pipe_path, 0600) == 0)
-#endif
- {
- debugserver_args.AppendArgument("--named-pipe");
- debugserver_args.AppendArgument(named_pipe_path);
- }
+ error = port_named_pipe.CreateNew(named_pipe_path, false);
+ if (error.Fail())
+ return error;
+ debugserver_args.AppendArgument("--named-pipe");
+ debugserver_args.AppendArgument(named_pipe_path);
}
}
else
@@ -838,11 +860,15 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
}
} while (has_env_var);
- // Close STDIN, STDOUT and STDERR. We might need to redirect them
- // to "/dev/null" if we run into any problems.
+ // Close STDIN, STDOUT and STDERR.
launch_info.AppendCloseFileAction (STDIN_FILENO);
launch_info.AppendCloseFileAction (STDOUT_FILENO);
launch_info.AppendCloseFileAction (STDERR_FILENO);
+
+ // Redirect STDIN, STDOUT and STDERR to "/dev/null".
+ launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false);
+ launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true);
+ launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true);
error = Host::LaunchProcess(launch_info);
@@ -850,20 +876,40 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
{
if (named_pipe_path[0])
{
- File name_pipe_file;
- error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead);
+ error = port_named_pipe.OpenAsReader(named_pipe_path, false);
if (error.Success())
{
char port_cstr[256];
port_cstr[0] = '\0';
size_t num_bytes = sizeof(port_cstr);
- error = name_pipe_file.Read(port_cstr, num_bytes);
- assert (error.Success());
- assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0');
- out_port = Args::StringToUInt32(port_cstr, 0);
- name_pipe_file.Close();
+ // 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 = Args::StringToUInt32(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, error.AsCString());
+
+ }
+ port_named_pipe.Close();
+ }
+ else
+ {
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() failed to open named pipe %s for reading: %s", __FUNCTION__, named_pipe_path, error.AsCString());
+ }
+ const auto err = port_named_pipe.Delete(named_pipe_path);
+ if (err.Fail())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s", __FUNCTION__, named_pipe_path, err.AsCString());
}
- FileSystem::Unlink(named_pipe_path);
}
else if (listen)
{
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
index b11d38563207..ac203a62788a 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -20,6 +20,7 @@
#include "lldb/lldb-public.h"
#include "lldb/Core/Communication.h"
#include "lldb/Core/Listener.h"
+#include "lldb/Host/HostThread.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Host/Predicate.h"
#include "lldb/Host/TimeValue.h"
@@ -281,8 +282,7 @@ protected:
ListenThread (lldb::thread_arg_t arg);
private:
-
- lldb::thread_t m_listen_thread;
+ lldb_private::HostThread m_listen_thread;
std::string m_listen_url;
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 5e4ed7648f95..52750de5a25f 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -20,11 +20,11 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "lldb/Interpreter/Args.h"
-#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamGDBRemote.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
@@ -1643,7 +1643,9 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)
}
else if (name.compare("triple") == 0)
{
- triple.swap(value);
+ extractor.GetStringRef ().swap (value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (triple);
++num_keys_decoded;
}
else if (name.compare ("distribution_id") == 0)
@@ -2331,6 +2333,10 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot
}
else if (name.compare("triple") == 0)
{
+ StringExtractor extractor;
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (value);
process_info.GetArchitecture ().SetTriple (value.c_str());
}
else if (name.compare("name") == 0)
@@ -2404,6 +2410,8 @@ GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceIn
bool
GDBRemoteCommunicationClient::GetCurrentProcessInfo ()
{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS));
+
if (m_qProcessInfo_is_valid == eLazyBoolYes)
return true;
if (m_qProcessInfo_is_valid == eLazyBoolNo)
@@ -2426,6 +2434,7 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo ()
std::string triple;
uint32_t pointer_byte_size = 0;
StringExtractor extractor;
+ ByteOrder byte_order = eByteOrderInvalid;
uint32_t num_keys_decoded = 0;
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
while (response.GetNameColonValue(name, value))
@@ -2444,7 +2453,10 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo ()
}
else if (name.compare("triple") == 0)
{
- triple = value;
+ StringExtractor extractor;
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (triple);
++num_keys_decoded;
}
else if (name.compare("ostype") == 0)
@@ -2459,10 +2471,15 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo ()
}
else if (name.compare("endian") == 0)
{
- if (value.compare("little") == 0 ||
- value.compare("big") == 0 ||
- value.compare("pdp") == 0)
- ++num_keys_decoded;
+ ++num_keys_decoded;
+ if (value.compare("little") == 0)
+ byte_order = eByteOrderLittle;
+ else if (value.compare("big") == 0)
+ byte_order = eByteOrderBig;
+ else if (value.compare("pdp") == 0)
+ byte_order = eByteOrderPDP;
+ else
+ --num_keys_decoded;
}
else if (name.compare("ptrsize") == 0)
{
@@ -2496,11 +2513,34 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo ()
}
else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty())
{
- m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub);
+ llvm::Triple triple(llvm::Twine("-") + vendor_name + "-" + os_name);
+
+ assert(triple.getObjectFormat() != llvm::Triple::UnknownObjectFormat);
+ switch (triple.getObjectFormat()) {
+ case llvm::Triple::MachO:
+ m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub);
+ break;
+ case llvm::Triple::ELF:
+ m_process_arch.SetArchitecture (eArchTypeELF, cpu, sub);
+ break;
+ case llvm::Triple::COFF:
+ m_process_arch.SetArchitecture (eArchTypeCOFF, cpu, sub);
+ break;
+ case llvm::Triple::UnknownObjectFormat:
+ if (log)
+ log->Printf("error: failed to determine target architecture");
+ return false;
+ }
+
if (pointer_byte_size)
{
assert (pointer_byte_size == m_process_arch.GetAddressByteSize());
}
+ if (byte_order != eByteOrderInvalid)
+ {
+ assert (byte_order == m_process_arch.GetByteOrder());
+ }
+ m_process_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name));
m_process_arch.GetTriple().setOSName(llvm::StringRef (os_name));
m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name));
m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name));
@@ -2931,6 +2971,11 @@ GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtracto
uint8_t
GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert, addr_t addr, uint32_t length)
{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64,
+ __FUNCTION__, insert ? "add" : "remove", addr);
+
// Check if the stub is known not to support this breakpoint type
if (!SupportsGDBStoppointPacket(type))
return UINT8_MAX;
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index ffcdd169eb9f..a7149505e869 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -23,11 +23,11 @@
// Other libraries and framework includes
#include "llvm/ADT/Triple.h"
#include "lldb/Interpreter/Args.h"
-#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Debug.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/File.h"
@@ -71,7 +71,7 @@ namespace
//----------------------------------------------------------------------
GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform),
- m_platform_sp (Platform::GetDefaultPlatform ()),
+ m_platform_sp (Platform::GetHostPlatform ()),
m_async_thread (LLDB_INVALID_HOST_THREAD),
m_process_launch_info (),
m_process_launch_error (),
@@ -429,6 +429,14 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
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);
+ break;
}
}
else
@@ -474,13 +482,34 @@ GDBRemoteCommunicationServer::LaunchProcess ()
// FIXME This looks an awful lot like we could override this in
// derived classes, one for lldb-platform, the other for lldb-gdbserver.
if (IsGdbServer ())
- return LaunchDebugServerProcess ();
+ 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::LaunchDebugServerProcess ()
+GDBRemoteCommunicationServer::LaunchProcessForDebugging ()
{
Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
@@ -503,20 +532,34 @@ GDBRemoteCommunicationServer::LaunchDebugServerProcess ()
return error;
}
- // Setup stdout/stderr mapping from inferior.
- auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor ();
- if (terminal_fd >= 0)
+ // 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 ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd);
- error = SetSTDIOFileDescriptor (terminal_fd);
- if (error.Fail ())
- return error;
+ 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 ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd);
+ 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 ());
@@ -526,33 +569,10 @@ GDBRemoteCommunicationServer::LaunchDebugServerProcess ()
if ((pid = m_process_launch_info.GetProcessID ()) != LLDB_INVALID_PROCESS_ID)
{
// add to spawned pids
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- // On an lldb-gdbserver, we would expect there to be only one.
- assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed");
- m_spawned_pids.insert (pid);
- }
- }
-
- if (error.Success ())
- {
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s beginning check to wait for launched application to hit first stop", __FUNCTION__);
-
- int iteration = 0;
- // Wait for the process to hit its first stop state.
- while (!StateIsStoppedState (m_debugged_process_sp->GetState (), false))
- {
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s waiting for launched process to hit first stop (%d)...", __FUNCTION__, iteration++);
-
- // FIXME use a finer granularity.
- std::this_thread::sleep_for(std::chrono::seconds(1));
- }
-
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s launched application has hit first stop", __FUNCTION__);
-
+ 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;
@@ -699,12 +719,18 @@ GDBRemoteCommunicationServer::SendWResponse (lldb_private::NativeProcessProtocol
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::eExitTypeExit:
+ return_type_code = 'W';
+ break;
+ case ExitType::eExitTypeSignal:
+ return_type_code = 'X';
+ break;
+ case ExitType::eExitTypeStop:
+ return_type_code = 'S';
+ break;
case ExitType::eExitTypeInvalid:
- default: return_type_code = 'E'; break;
+ return_type_code = 'E';
+ break;
}
response.PutChar (return_type_code);
@@ -861,21 +887,21 @@ GDBRemoteCommunicationServer::SendStopReplyPacketForThread (lldb::tid_t tid)
response.Printf ("thread:%" PRIx64 ";", tid);
// Include the thread name if there is one.
- const char *thread_name = thread_sp->GetName ();
- if (thread_name && thread_name[0])
+ const std::string thread_name = thread_sp->GetName ();
+ if (!thread_name.empty ())
{
- size_t thread_name_len = strlen(thread_name);
+ size_t thread_name_len = thread_name.length ();
- if (::strcspn (thread_name, "$#+-;:") == thread_name_len)
+ if (::strcspn (thread_name.c_str (), "$#+-;:") == thread_name_len)
{
response.PutCString ("name:");
- response.PutCString (thread_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);
+ response.PutCStringAsRawHex8 (thread_name.c_str ());
}
response.PutChar (';');
}
@@ -1197,7 +1223,7 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet
ArchSpec host_arch(HostInfo::GetArchitecture());
const llvm::Triple &host_triple = host_arch.GetTriple();
response.PutCString("triple:");
- response.PutCString(host_triple.getTriple().c_str());
+ response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
const char* distribution_id = host_arch.GetDistributionId ().AsCString ();
@@ -1252,7 +1278,6 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet
}
std::string s;
-#if !defined(__linux__)
if (HostInfo::GetOSBuildString(s))
{
response.PutCString ("os_build:");
@@ -1265,7 +1290,6 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet
response.PutCStringAsRawHex8(s.c_str());
response.PutChar(';');
}
-#endif
#if defined(__APPLE__)
@@ -1315,7 +1339,7 @@ CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &r
{
const llvm::Triple &proc_triple = proc_arch.GetTriple();
response.PutCString("triple:");
- response.PutCString(proc_triple.getTriple().c_str());
+ response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
response.PutChar(';');
}
}
@@ -1351,7 +1375,10 @@ CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info
response.Printf ("vendor:%s;", vendor.c_str ());
#else
// We'll send the triple.
- response.Printf ("triple:%s;", proc_triple.getTriple().c_str ());
+ 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.
@@ -2372,8 +2399,6 @@ GDBRemoteCommunicationServer::Handle_vCont_actions (StringExtractorGDBRemote &pa
return SendUnimplementedResponse (packet.GetStringRef().c_str());
}
- // We handle $vCont messages for c.
- // TODO add C, s and S.
StreamString response;
response.Printf("vCont;c;C;s;S");
@@ -3388,10 +3413,8 @@ GDBRemoteCommunicationServer::Handle_interrupt (StringExtractorGDBRemote &packet
return SendErrorResponse (0x15);
}
- // Build the ResumeActionList - stop everything.
- lldb_private::ResumeActionList actions (StateType::eStateStopped, 0);
-
- Error error = m_debugged_process_sp->Resume (actions);
+ // Interrupt the process.
+ Error error = m_debugged_process_sp->Interrupt ();
if (error.Fail ())
{
if (log)
@@ -3771,7 +3794,7 @@ GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet)
}
// Parse out software or hardware breakpoint requested.
- packet.SetFilePos (strlen("Z"));
+ packet.SetFilePos (strlen("z"));
if (packet.GetBytesLeft() < 1)
return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier");
@@ -3811,7 +3834,7 @@ GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet)
if (want_breakpoint)
{
- // Try to set the breakpoint.
+ // Try to clear the breakpoint.
const Error error = m_debugged_process_sp->RemoveBreakpoint (breakpoint_addr);
if (error.Success ())
return SendOKResponse ();
@@ -4171,8 +4194,93 @@ GDBRemoteCommunicationServer::Handle_vAttach (StringExtractorGDBRemote &packet)
// Notify we attached by sending a stop packet.
return SendStopReasonForState (m_debugged_process_sp->GetState (), true);
+}
- return PacketResult::Success;
+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);
}
void
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
index 13c037c0287b..07ce98e29ac6 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -58,7 +58,7 @@ public:
bool &quit);
virtual bool
- GetThreadSuffixSupported ()
+ GetThreadSuffixSupported () override
{
return true;
}
@@ -152,8 +152,6 @@ public:
//------------------------------------------------------------------
/// Specify the program to launch and its arguments.
///
- /// The LaunchProcess () command can be executed to do the lauching.
- ///
/// @param[in] args
/// The command line to launch.
///
@@ -170,8 +168,6 @@ public:
//------------------------------------------------------------------
/// Specify the launch flags for the process.
///
- /// The LaunchProcess () command can be executed to do the lauching.
- ///
/// @param[in] launch_flags
/// The launch flags to use when launching this process.
///
@@ -463,6 +459,12 @@ protected:
PacketResult
Handle_vAttach (StringExtractorGDBRemote &packet);
+ PacketResult
+ Handle_D (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qThreadStopInfo (StringExtractorGDBRemote &packet);
+
void
SetCurrentThreadID (lldb::tid_t tid);
@@ -511,9 +513,9 @@ private:
return !m_is_platform;
}
- /// Launch a process from lldb-gdbserver
+ /// Launch an inferior process from lldb-gdbserver
lldb_private::Error
- LaunchDebugServerProcess ();
+ LaunchProcessForDebugging ();
/// Launch a process from lldb-platform
lldb_private::Error
@@ -540,6 +542,9 @@ private:
void
ClearProcessSpecificData ();
+ bool
+ ShouldRedirectInferiorOutputOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const;
+
//------------------------------------------------------------------
// For GDBRemoteCommunicationServer only
//------------------------------------------------------------------
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index f35d954caa7b..fe99706969c8 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -14,7 +14,6 @@
#include <errno.h>
#include <stdlib.h>
#ifndef LLDB_DISABLE_POSIX
-#include <spawn.h>
#include <netinet/in.h>
#include <sys/mman.h> // for mmap
#endif
@@ -32,7 +31,7 @@
#include "lldb/Interpreter/Args.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
@@ -42,7 +41,9 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
#include "lldb/Core/Value.h"
+#include "lldb/Host/HostThread.h"
#include "lldb/Host/Symbols.h"
+#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Host/TimeValue.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
@@ -272,8 +273,6 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
m_last_stop_packet_mutex (Mutex::eMutexTypeNormal),
m_register_info (),
m_async_broadcaster (NULL, "lldb.process.gdb-remote.async-broadcaster"),
- m_async_thread (LLDB_INVALID_HOST_THREAD),
- m_async_thread_state(eAsyncThreadNotStarted),
m_async_thread_state_mutex(Mutex::eMutexTypeRecursive),
m_thread_ids (),
m_continue_c_tids (),
@@ -749,8 +748,12 @@ ProcessGDBRemote::WillLaunchOrAttach ()
Error
ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
Error error;
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s() entered", __FUNCTION__);
+
uint32_t launch_flags = launch_info.GetFlags().Get();
const char *stdin_path = NULL;
const char *stdout_path = NULL;
@@ -777,10 +780,21 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
stderr_path = file_action->GetPath();
}
+ 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",
+ __FUNCTION__,
+ stdin_path ? stdin_path : "<null>",
+ stdout_path ? stdout_path : "<null>",
+ stderr_path ? stderr_path : "<null>");
+ else
+ log->Printf ("ProcessGDBRemote::%s no STDIO paths given via launch_info", __FUNCTION__);
+ }
+
// ::LogSetBitMask (GDBR_LOG_DEFAULT);
// ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
// ::LogSetLogFile ("/dev/stdout");
- Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
ObjectFile * object_file = exe_module->GetObjectFile();
if (object_file)
@@ -817,6 +831,13 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
if (stderr_path == NULL)
stderr_path = 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",
+ __FUNCTION__,
+ stdin_path ? stdin_path : "<null>",
+ stdout_path ? stdout_path : "<null>",
+ stderr_path ? stderr_path : "<null>");
}
// Set STDIN to /dev/null if we want STDIO disabled or if either
@@ -834,7 +855,14 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
if (disable_stdio || (stderr_path == NULL && (stdin_path || stdout_path)))
stderr_path = "/dev/null";
- if (stdin_path)
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s final STDIO paths after all adjustments: stdin=%s, stdout=%s, stdout=%s",
+ __FUNCTION__,
+ stdin_path ? stdin_path : "<null>",
+ stdout_path ? stdout_path : "<null>",
+ stderr_path ? stderr_path : "<null>");
+
+ if (stdin_path)
m_gdb_comm.SetSTDIN (stdin_path);
if (stdout_path)
m_gdb_comm.SetSTDOUT (stdout_path);
@@ -1026,18 +1054,38 @@ ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch)
// prefer that over the Host information as it will be more specific
// to our process.
- if (m_gdb_comm.GetProcessArchitecture().IsValid())
- process_arch = m_gdb_comm.GetProcessArchitecture();
+ const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture();
+ if (remote_process_arch.IsValid())
+ {
+ process_arch = remote_process_arch;
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s gdb-remote had process architecture, using %s %s",
+ __FUNCTION__,
+ process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>",
+ process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>");
+ }
else
+ {
process_arch = m_gdb_comm.GetHostArchitecture();
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s gdb-remote did not have process architecture, using gdb-remote host architecture %s %s",
+ __FUNCTION__,
+ process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>",
+ process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>");
+ }
if (process_arch.IsValid())
{
ArchSpec &target_arch = GetTarget().GetArchitecture();
-
if (target_arch.IsValid())
{
- // If the remote host is ARM and we have apple as the vendor, then
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s analyzing target arch, currently %s %s",
+ __FUNCTION__,
+ target_arch.GetArchitectureName () ? target_arch.GetArchitectureName () : "<null>",
+ target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : "<null>");
+
+ // If the remote host is ARM and we have apple as the vendor, then
// ARM executables and shared libraries can have mixed ARM architectures.
// You can have an armv6 executable, and if the host is armv7, then the
// system will load the best possible architecture for all shared libraries
@@ -1048,6 +1096,11 @@ ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch)
process_arch.GetTriple().getVendor() == llvm::Triple::Apple)
{
GetTarget().SetArchitecture (process_arch);
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s remote process is ARM/Apple, setting target arch to %s %s",
+ __FUNCTION__,
+ process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>",
+ process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>");
}
else
{
@@ -1066,7 +1119,14 @@ ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch)
target_triple.setEnvironment (remote_triple.getEnvironment());
}
}
+
}
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s final target arch after adjustments for remote architecture: %s %s",
+ __FUNCTION__,
+ target_arch.GetArchitectureName () ? target_arch.GetArchitectureName () : "<null>",
+ target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : "<null>");
}
else
{
@@ -1095,7 +1155,12 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid)
Error
ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info)
{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
Error error;
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s()", __FUNCTION__);
+
// Clear out and clean up from any current state
Clear();
if (attach_pid != LLDB_INVALID_PROCESS_ID)
@@ -1118,13 +1183,14 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process
if (error.Success())
{
m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
-
+
char packet[64];
const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid);
SetID (attach_pid);
m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet, packet_len));
}
}
+
return error;
}
@@ -1432,7 +1498,7 @@ ProcessGDBRemote::DoResume ()
TimeValue timeout;
timeout = TimeValue::Now();
timeout.OffsetWithSeconds (5);
- if (!IS_VALID_LLDB_HOST_THREAD(m_async_thread))
+ if (!m_async_thread.IsJoinable())
{
error.SetErrorString ("Trying to resume but the async thread is dead.");
if (log)
@@ -2891,30 +2957,17 @@ ProcessGDBRemote::StartAsyncThread ()
log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
Mutex::Locker start_locker(m_async_thread_state_mutex);
- if (m_async_thread_state == eAsyncThreadNotStarted)
+ if (!m_async_thread.IsJoinable())
{
// Create a thread that watches our internal state and controls which
// events make it to clients (into the DCProcess event queue).
- m_async_thread = Host::ThreadCreate ("<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this, NULL);
- if (IS_VALID_LLDB_HOST_THREAD(m_async_thread))
- {
- m_async_thread_state = eAsyncThreadRunning;
- return true;
- }
- else
- return false;
- }
- else
- {
- // Somebody tried to start the async thread while it was either being started or stopped. If the former, and
- // it started up successfully, then say all's well. Otherwise it is an error, since we aren't going to restart it.
- if (log)
- log->Printf ("ProcessGDBRemote::%s () - Called when Async thread was in state: %d.", __FUNCTION__, m_async_thread_state);
- if (m_async_thread_state == eAsyncThreadRunning)
- return true;
- else
- return false;
+
+ m_async_thread = ThreadLauncher::LaunchThread("<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this, NULL);
}
+ else if (log)
+ log->Printf("ProcessGDBRemote::%s () - Called when Async thread was already running.", __FUNCTION__);
+
+ return m_async_thread.IsJoinable();
}
void
@@ -2926,7 +2979,7 @@ ProcessGDBRemote::StopAsyncThread ()
log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
Mutex::Locker start_locker(m_async_thread_state_mutex);
- if (m_async_thread_state == eAsyncThreadRunning)
+ if (m_async_thread.IsJoinable())
{
m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit);
@@ -2934,17 +2987,10 @@ ProcessGDBRemote::StopAsyncThread ()
m_gdb_comm.Disconnect(); // Disconnect from the debug server.
// Stop the stdio thread
- if (IS_VALID_LLDB_HOST_THREAD(m_async_thread))
- {
- Host::ThreadJoin (m_async_thread, NULL, NULL);
- }
- m_async_thread_state = eAsyncThreadDone;
- }
- else
- {
- if (log)
- log->Printf ("ProcessGDBRemote::%s () - Called when Async thread was in state: %d.", __FUNCTION__, m_async_thread_state);
+ m_async_thread.Join(nullptr);
}
+ else if (log)
+ log->Printf("ProcessGDBRemote::%s () - Called when Async thread was not running.", __FUNCTION__);
}
@@ -3086,7 +3132,7 @@ ProcessGDBRemote::AsyncThread (void *arg)
if (log)
log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, arg, process->GetID());
- process->m_async_thread = LLDB_INVALID_HOST_THREAD;
+ process->m_async_thread.Reset();
return NULL;
}
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 942b31c84dde..e0c460a202d6 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -25,6 +25,7 @@
#include "lldb/Core/StringList.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Host/HostThread.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"
@@ -74,148 +75,148 @@ public:
//------------------------------------------------------------------
virtual bool
CanDebug (lldb_private::Target &target,
- bool plugin_specified_by_name);
+ bool plugin_specified_by_name) override;
virtual lldb_private::CommandObject *
- GetPluginCommandObject();
+ GetPluginCommandObject() override;
//------------------------------------------------------------------
// Creating a new process, or attaching to an existing one
//------------------------------------------------------------------
virtual lldb_private::Error
- WillLaunch (lldb_private::Module* module);
+ WillLaunch (lldb_private::Module* module) override;
virtual lldb_private::Error
DoLaunch (lldb_private::Module *exe_module,
- lldb_private::ProcessLaunchInfo &launch_info);
+ lldb_private::ProcessLaunchInfo &launch_info) override;
virtual void
- DidLaunch ();
+ DidLaunch () override;
virtual lldb_private::Error
- WillAttachToProcessWithID (lldb::pid_t pid);
+ WillAttachToProcessWithID (lldb::pid_t pid) override;
virtual lldb_private::Error
- WillAttachToProcessWithName (const char *process_name, bool wait_for_launch);
+ WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) override;
virtual lldb_private::Error
- DoConnectRemote (lldb_private::Stream *strm, const char *remote_url);
+ DoConnectRemote (lldb_private::Stream *strm, const char *remote_url) override;
lldb_private::Error
WillLaunchOrAttach ();
virtual lldb_private::Error
- DoAttachToProcessWithID (lldb::pid_t pid);
+ DoAttachToProcessWithID (lldb::pid_t pid) override;
virtual lldb_private::Error
- DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info);
+ DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override;
virtual lldb_private::Error
DoAttachToProcessWithName (const char *process_name,
- const lldb_private::ProcessAttachInfo &attach_info);
+ const lldb_private::ProcessAttachInfo &attach_info) override;
virtual void
- DidAttach (lldb_private::ArchSpec &process_arch);
+ DidAttach (lldb_private::ArchSpec &process_arch) override;
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
virtual lldb_private::ConstString
- GetPluginName();
+ GetPluginName() override;
virtual uint32_t
- GetPluginVersion();
+ GetPluginVersion() override;
//------------------------------------------------------------------
// Process Control
//------------------------------------------------------------------
virtual lldb_private::Error
- WillResume ();
+ WillResume () override;
virtual lldb_private::Error
- DoResume ();
+ DoResume () override;
virtual lldb_private::Error
- DoHalt (bool &caused_stop);
+ DoHalt (bool &caused_stop) override;
virtual lldb_private::Error
- DoDetach (bool keep_stopped);
+ DoDetach (bool keep_stopped) override;
virtual bool
- DetachRequiresHalt() { return true; }
+ DetachRequiresHalt() override { return true; }
virtual lldb_private::Error
- DoSignal (int signal);
+ DoSignal (int signal) override;
virtual lldb_private::Error
- DoDestroy ();
+ DoDestroy () override;
virtual void
- RefreshStateAfterStop();
+ RefreshStateAfterStop() override;
//------------------------------------------------------------------
// Process Queries
//------------------------------------------------------------------
virtual bool
- IsAlive ();
+ IsAlive () override;
virtual lldb::addr_t
- GetImageInfoAddress();
+ GetImageInfoAddress() override;
//------------------------------------------------------------------
// Process Memory
//------------------------------------------------------------------
virtual size_t
- DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
virtual size_t
- DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error);
+ DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error) override;
virtual lldb::addr_t
- DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error);
+ DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error) override;
virtual lldb_private::Error
GetMemoryRegionInfo (lldb::addr_t load_addr,
- lldb_private::MemoryRegionInfo &region_info);
+ lldb_private::MemoryRegionInfo &region_info) override;
virtual lldb_private::Error
- DoDeallocateMemory (lldb::addr_t ptr);
+ DoDeallocateMemory (lldb::addr_t ptr) override;
//------------------------------------------------------------------
// Process STDIO
//------------------------------------------------------------------
virtual size_t
- PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error);
+ PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error) override;
//----------------------------------------------------------------------
// Process Breakpoints
//----------------------------------------------------------------------
virtual lldb_private::Error
- EnableBreakpointSite (lldb_private::BreakpointSite *bp_site);
+ EnableBreakpointSite (lldb_private::BreakpointSite *bp_site) override;
virtual lldb_private::Error
- DisableBreakpointSite (lldb_private::BreakpointSite *bp_site);
+ DisableBreakpointSite (lldb_private::BreakpointSite *bp_site) override;
//----------------------------------------------------------------------
// Process Watchpoints
//----------------------------------------------------------------------
virtual lldb_private::Error
- EnableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true);
+ EnableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true) override;
virtual lldb_private::Error
- DisableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true);
+ DisableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true) override;
virtual lldb_private::Error
- GetWatchpointSupportInfo (uint32_t &num);
+ GetWatchpointSupportInfo (uint32_t &num) override;
virtual lldb_private::Error
- GetWatchpointSupportInfo (uint32_t &num, bool& after);
+ GetWatchpointSupportInfo (uint32_t &num, bool& after) override;
virtual bool
- StartNoticingNewThreads();
+ StartNoticingNewThreads() override;
virtual bool
- StopNoticingNewThreads();
+ StopNoticingNewThreads() override;
GDBRemoteCommunicationClient &
GetGDBRemote()
@@ -224,13 +225,13 @@ public:
}
virtual lldb_private::Error
- SendEventData(const char *data);
+ SendEventData(const char *data) override;
//----------------------------------------------------------------------
// Override SetExitStatus so we can disconnect from the remote GDB server
//----------------------------------------------------------------------
virtual bool
- SetExitStatus (int exit_status, const char *cstr);
+ SetExitStatus (int exit_status, const char *cstr) override;
void
SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max);
@@ -286,7 +287,7 @@ protected:
virtual bool
UpdateThreadList (lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list);
+ lldb_private::ThreadList &new_thread_list) override;
lldb_private::Error
LaunchAndConnectToDebugserver (const lldb_private::ProcessInfo &process_info);
@@ -324,23 +325,15 @@ protected:
eBroadcastBitAsyncThreadShouldExit = (1 << 1),
eBroadcastBitAsyncThreadDidExit = (1 << 2)
};
-
- typedef enum AsyncThreadState
- {
- eAsyncThreadNotStarted,
- eAsyncThreadRunning,
- eAsyncThreadDone
- } AsyncThreadState;
lldb_private::Flags m_flags; // Process specific flags (see eFlags enums)
GDBRemoteCommunicationClient m_gdb_comm;
- lldb::pid_t m_debugserver_pid;
+ std::atomic<lldb::pid_t> m_debugserver_pid;
StringExtractorGDBRemote m_last_stop_packet;
lldb_private::Mutex m_last_stop_packet_mutex;
GDBRemoteDynamicRegisterInfo m_register_info;
lldb_private::Broadcaster m_async_broadcaster;
- lldb::thread_t m_async_thread;
- AsyncThreadState m_async_thread_state;
+ lldb_private::HostThread m_async_thread;
lldb_private::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;
@@ -395,7 +388,7 @@ protected:
std::string &dispatch_queue_name);
lldb_private::DynamicLoader *
- GetDynamicLoader ();
+ GetDynamicLoader () override;
private:
//------------------------------------------------------------------
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
index bc2e7a62b76e..14fc2cea2329 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
@@ -73,14 +73,14 @@ DWARFAbbreviationDeclaration::Extract(const DWARFDataExtractor& data, lldb::offs
void
DWARFAbbreviationDeclaration::Dump(Stream *s) const
{
-// *ostrm_ptr << std::setfill(' ') << std::dec << '[' << std::setw(3) << std::right << m_code << ']' << ' ' << std::setw(30) << std::left << DW_TAG_value_to_name(m_tag) << DW_CHILDREN_value_to_name(m_has_children) << std::endl;
-//
-// DWARFAttribute::const_iterator pos;
-//
-// for (pos = m_attributes.begin(); pos != m_attributes.end(); ++pos)
-// *ostrm_ptr << " " << std::setw(29) << std::left << DW_AT_value_to_name(pos->attr()) << ' ' << DW_FORM_value_to_name(pos->form()) << std::endl;
-//
-// *ostrm_ptr << std::endl;
+ s->Printf("Debug Abbreviation Declaration: code = 0x%4.4x, tag = %s, has_children = %s\n", m_code, DW_TAG_value_to_name(m_tag), DW_CHILDREN_value_to_name(m_has_children));
+
+ DWARFAttribute::const_iterator pos;
+
+ for (pos = m_attributes.begin(); pos != m_attributes.end(); ++pos)
+ s->Printf(" attr = %s, form = %s\n", DW_AT_value_to_name(pos->get_attr()), DW_FORM_value_to_name(pos->get_form()));
+
+ s->Printf("\n");
}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
index b2e64ad9f8c8..067449a289be 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -49,7 +49,8 @@ DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF* dwarf2Data) :
m_producer (eProducerInvalid),
m_producer_version_major (0),
m_producer_version_minor (0),
- m_producer_version_update (0)
+ m_producer_version_update (0),
+ m_is_dwarf64 (false)
{
}
@@ -66,6 +67,7 @@ DWARFCompileUnit::Clear()
m_func_aranges_ap.reset();
m_user_data = NULL;
m_producer = eProducerInvalid;
+ m_is_dwarf64 = false;
}
bool
@@ -79,9 +81,10 @@ DWARFCompileUnit::Extract(const DWARFDataExtractor &debug_info, lldb::offset_t *
{
dw_offset_t abbr_offset;
const DWARFDebugAbbrev *abbr = m_dwarf2Data->DebugAbbrev();
- m_length = debug_info.GetU32(offset_ptr);
+ m_length = debug_info.GetDWARFInitialLength(offset_ptr);
+ m_is_dwarf64 = debug_info.IsDWARF64();
m_version = debug_info.GetU16(offset_ptr);
- abbr_offset = debug_info.GetU32(offset_ptr);
+ abbr_offset = debug_info.GetDWARFOffset(offset_ptr);
m_addr_size = debug_info.GetU8 (offset_ptr);
bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset()-1);
@@ -168,7 +171,7 @@ DWARFCompileUnit::ExtractDIEsIfNeeded (bool cu_die_only)
die_index_stack.reserve(32);
die_index_stack.push_back(0);
bool prev_die_had_children = false;
- const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize());
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize(), m_is_dwarf64);
while (offset < next_cu_offset &&
die.FastExtract (debug_info_data, this, fixed_form_sizes, &offset))
{
@@ -347,6 +350,14 @@ DWARFCompileUnit::GetAddressByteSize(const DWARFCompileUnit* cu)
return DWARFCompileUnit::GetDefaultAddressSize();
}
+bool
+DWARFCompileUnit::IsDWARF64(const DWARFCompileUnit* cu)
+{
+ if (cu)
+ return cu->IsDWARF64();
+ return false;
+}
+
uint8_t
DWARFCompileUnit::GetDefaultAddressSize()
{
@@ -619,7 +630,7 @@ DWARFCompileUnit::Index (const uint32_t cu_idx,
{
const DWARFDataExtractor* debug_str = &m_dwarf2Data->get_debug_str_data();
- const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize());
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize(), m_is_dwarf64);
Log *log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_LOOKUPS));
@@ -761,7 +772,7 @@ DWARFCompileUnit::Index (const uint32_t cu_idx,
case DW_AT_specification:
if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
- specification_die_offset = form_value.Reference(this);
+ specification_die_offset = form_value.Reference();
break;
}
}
@@ -1030,3 +1041,9 @@ DWARFCompileUnit::GetProducerVersionUpdate()
return m_producer_version_update;
}
+bool
+DWARFCompileUnit::IsDWARF64() const
+{
+ return m_is_dwarf64;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
index ed1894b8a9f6..3e904892dbd5 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
@@ -41,11 +41,11 @@ public:
bool Verify(lldb_private::Stream *s) const;
void Dump(lldb_private::Stream *s) const;
dw_offset_t GetOffset() const { return m_offset; }
- uint32_t Size() const { return 11; /* Size in bytes of the compile unit header */ }
+ uint32_t Size() const { return m_is_dwarf64 ? 23 : 11; /* Size in bytes of the compile unit header */ }
bool ContainsDIEOffset(dw_offset_t die_offset) const { return die_offset >= GetFirstDIEOffset() && die_offset < GetNextCompileUnitOffset(); }
dw_offset_t GetFirstDIEOffset() const { return m_offset + Size(); }
- dw_offset_t GetNextCompileUnitOffset() const { return m_offset + m_length + 4; }
- size_t GetDebugInfoSize() const { return m_length + 4 - Size(); /* Size in bytes of the .debug_info data associated with this compile unit. */ }
+ dw_offset_t GetNextCompileUnitOffset() const { return m_offset + m_length + (m_is_dwarf64 ? 12 : 4); }
+ size_t GetDebugInfoSize() const { return m_length + (m_is_dwarf64 ? 12 : 4) - Size(); /* Size in bytes of the .debug_info data associated with this compile unit. */ }
uint32_t GetLength() const { return m_length; }
uint16_t GetVersion() const { return m_version; }
const DWARFAbbreviationDeclarationSet* GetAbbreviations() const { return m_abbrevs; }
@@ -118,6 +118,9 @@ public:
static uint8_t
GetAddressByteSize(const DWARFCompileUnit* cu);
+ static bool
+ IsDWARF64(const DWARFCompileUnit* cu);
+
static uint8_t
GetDefaultAddressSize();
@@ -183,6 +186,9 @@ public:
uint32_t
GetProducerVersionUpdate();
+ bool
+ IsDWARF64() const;
+
protected:
SymbolFileDWARF* m_dwarf2Data;
const DWARFAbbreviationDeclarationSet *m_abbrevs;
@@ -191,13 +197,14 @@ protected:
std::unique_ptr<DWARFDebugAranges> m_func_aranges_ap; // A table similar to the .debug_aranges table, but this one points to the exact DW_TAG_subprogram DIEs
dw_addr_t m_base_addr;
dw_offset_t m_offset;
- uint32_t m_length;
+ dw_offset_t m_length;
uint16_t m_version;
uint8_t m_addr_size;
Producer m_producer;
uint32_t m_producer_version_major;
uint32_t m_producer_version_minor;
uint32_t m_producer_version_update;
+ bool m_is_dwarf64;
void
ParseProducerInfo ();
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
index 6e5b974a71ff..ba2e8ad08acc 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
@@ -33,6 +33,9 @@ public:
size_t
GetDWARFSizeofInitialLength() const { return m_is_dwarf64 ? 12 : 4; }
+ bool
+ IsDWARF64() const { return m_is_dwarf64; }
+
protected:
mutable bool m_is_dwarf64;
};
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
index a8c553e2d2ca..393434800c01 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -555,8 +555,15 @@ static dw_offset_t DumpCallback
if (dumpInfo->die_offset == DW_INVALID_OFFSET)
{
// We are dumping everything
- cu->Dump(s);
- return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this Compile Unit
+ if (cu)
+ {
+ cu->Dump(s);
+ return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this Compile Unit
+ }
+ else
+ {
+ return DW_INVALID_OFFSET;
+ }
}
else
{
@@ -568,7 +575,7 @@ static dw_offset_t DumpCallback
// We are dumping only a single DIE possibly with it's children and
// we must find it's compile unit before we can dump it properly
- if (dumpInfo->die_offset < cu->GetFirstDIEOffset())
+ if (cu && dumpInfo->die_offset < cu->GetFirstDIEOffset())
{
// Not found, maybe the DIE offset provided wasn't correct?
// *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " was not found." << endl;
@@ -577,7 +584,7 @@ static dw_offset_t DumpCallback
else
{
// See if the DIE is in this compile unit?
- if (dumpInfo->die_offset < cu->GetNextCompileUnitOffset())
+ if (cu && dumpInfo->die_offset < cu->GetNextCompileUnitOffset())
{
// This DIE is in this compile unit!
if (s->GetVerbose())
@@ -590,7 +597,14 @@ static dw_offset_t DumpCallback
else
{
// Skip to the next compile unit as the DIE isn't in the current one!
- return cu->GetNextCompileUnitOffset();
+ if (cu)
+ {
+ return cu->GetNextCompileUnitOffset();
+ }
+ else
+ {
+ return DW_INVALID_OFFSET;
+ }
}
}
}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
index 856a7fa7a2ff..10b51ffe0a8a 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -88,9 +88,10 @@ DWARFDebugInfoEntry::Attributes::RemoveAttribute(dw_attr_t attr)
bool
DWARFDebugInfoEntry::Attributes::ExtractFormValueAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, DWARFFormValue &form_value) const
{
+ form_value.SetCompileUnit(CompileUnitAtIndex(i));
form_value.SetForm(FormAtIndex(i));
lldb::offset_t offset = DIEOffsetAtIndex(i);
- return form_value.ExtractValue(dwarf2Data->get_debug_info_data(), &offset, CompileUnitAtIndex(i));
+ return form_value.ExtractValue(dwarf2Data->get_debug_info_data(), &offset);
}
uint64_t
@@ -107,7 +108,7 @@ DWARFDebugInfoEntry::Attributes::FormValueAsUnsignedAtIndex(SymbolFileDWARF* dwa
{
DWARFFormValue form_value;
if (ExtractFormValueAtIndex(dwarf2Data, i, form_value))
- return form_value.Reference(CompileUnitAtIndex(i));
+ return form_value.Reference();
return fail_value;
}
@@ -190,7 +191,7 @@ DWARFDebugInfoEntry::FastExtract
if (cu->GetVersion() <= 2)
form_size = cu->GetAddressByteSize();
else
- form_size = 4; // 4 bytes for DWARF 32, 8 bytes for DWARF 64, but we don't support DWARF64 yet
+ form_size = cu->IsDWARF64() ? 8 : 4;
break;
// 0 sized form
@@ -212,7 +213,6 @@ DWARFDebugInfoEntry::FastExtract
break;
// 4 byte values
- case DW_FORM_strp :
case DW_FORM_data4 :
case DW_FORM_ref4 :
form_size = 4;
@@ -237,11 +237,12 @@ DWARFDebugInfoEntry::FastExtract
form = debug_info_data.GetULEB128 (&offset);
break;
+ case DW_FORM_strp :
case DW_FORM_sec_offset :
- if (cu->GetAddressByteSize () == 4)
- debug_info_data.GetU32 (offset_ptr);
- else
+ if (cu->IsDWARF64 ())
debug_info_data.GetU64 (offset_ptr);
+ else
+ debug_info_data.GetU32 (offset_ptr);
break;
default:
@@ -284,7 +285,6 @@ DWARFDebugInfoEntry::Extract
const DWARFDataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
// const DWARFDataExtractor& debug_str_data = dwarf2Data->get_debug_str_data();
const uint32_t cu_end_offset = cu->GetNextCompileUnitOffset();
- const uint8_t cu_addr_size = cu->GetAddressByteSize();
lldb::offset_t offset = *offset_ptr;
// if (offset >= cu_end_offset)
// Log::Error("DIE at offset 0x%8.8x is beyond the end of the current compile unit (0x%8.8x)", m_offset, cu_end_offset);
@@ -319,8 +319,8 @@ DWARFDebugInfoEntry::Extract
if (isCompileUnitTag && ((attr == DW_AT_entry_pc) || (attr == DW_AT_low_pc)))
{
- DWARFFormValue form_value(form);
- if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ DWARFFormValue form_value(cu, form);
+ if (form_value.ExtractValue(debug_info_data, &offset))
{
if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc)
((DWARFCompileUnit*)cu)->SetBaseAddress(form_value.Unsigned());
@@ -348,13 +348,13 @@ DWARFDebugInfoEntry::Extract
// Compile unit address sized values
case DW_FORM_addr :
- form_size = cu_addr_size;
+ form_size = cu->GetAddressByteSize();
break;
case DW_FORM_ref_addr :
if (cu->GetVersion() <= 2)
- form_size = cu_addr_size;
+ form_size = cu->GetAddressByteSize();
else
- form_size = 4; // 4 bytes for DWARF 32, 8 bytes for DWARF 64, but we don't support DWARF64 yet
+ form_size = cu->IsDWARF64() ? 8 : 4;
break;
// 0 sized form
@@ -376,10 +376,6 @@ DWARFDebugInfoEntry::Extract
break;
// 4 byte values
- case DW_FORM_strp :
- form_size = 4;
- break;
-
case DW_FORM_data4 :
case DW_FORM_ref4 :
form_size = 4;
@@ -404,11 +400,12 @@ DWARFDebugInfoEntry::Extract
form_is_indirect = true;
break;
+ case DW_FORM_strp :
case DW_FORM_sec_offset :
- if (cu->GetAddressByteSize () == 4)
- debug_info_data.GetU32 (offset_ptr);
- else
+ if (cu->IsDWARF64 ())
debug_info_data.GetU64 (offset_ptr);
+ else
+ debug_info_data.GetU32 (offset_ptr);
break;
default:
@@ -781,8 +778,8 @@ DWARFDebugInfoEntry::GetDIENamesAndRanges
for (i=0; i<numAttributes; ++i)
{
abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
- DWARFFormValue form_value(form);
- if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ DWARFFormValue form_value(cu, form);
+ if (form_value.ExtractValue(debug_info_data, &offset))
{
switch (attr)
{
@@ -832,11 +829,11 @@ DWARFDebugInfoEntry::GetDIENamesAndRanges
break;
case DW_AT_abstract_origin:
- die_offsets.push_back(form_value.Reference(cu));
+ die_offsets.push_back(form_value.Reference());
break;
case DW_AT_specification:
- die_offsets.push_back(form_value.Reference(cu));
+ die_offsets.push_back(form_value.Reference());
break;
case DW_AT_decl_file:
@@ -1033,7 +1030,7 @@ DWARFDebugInfoEntry::DumpLocation
const char *obj_file_name = NULL;
ObjectFile *obj_file = dwarf2Data->GetObjectFile();
if (obj_file)
- obj_file_name = obj_file->GetFileSpec().GetFilename().AsCString();
+ obj_file_name = obj_file->GetFileSpec().GetFilename().AsCString("<Unknown>");
const char *die_name = GetName (dwarf2Data, cu);
s.Printf ("0x%8.8x/0x%8.8x: %-30s (from %s in %s)",
cu->GetOffset(),
@@ -1077,9 +1074,9 @@ DWARFDebugInfoEntry::DumpAttribute
s.Printf( "[%s", DW_FORM_value_to_name(form));
}
- DWARFFormValue form_value(form);
+ DWARFFormValue form_value(cu, form);
- if (!form_value.ExtractValue(debug_info_data, offset_ptr, cu))
+ if (!form_value.ExtractValue(debug_info_data, offset_ptr))
return;
if (show_form)
@@ -1097,7 +1094,7 @@ DWARFDebugInfoEntry::DumpAttribute
// Always dump form value if verbose is enabled
if (verbose)
{
- form_value.Dump(s, debug_str_data, cu);
+ form_value.Dump(s, debug_str_data);
}
@@ -1130,7 +1127,7 @@ DWARFDebugInfoEntry::DumpAttribute
if (blockData)
{
if (!verbose)
- form_value.Dump(s, debug_str_data, cu);
+ form_value.Dump(s, debug_str_data);
// Location description is inlined in data in the form value
DWARFDataExtractor locationData(debug_info_data, (*offset_ptr) - form_value.Unsigned(), form_value.Unsigned());
@@ -1147,13 +1144,13 @@ DWARFDebugInfoEntry::DumpAttribute
if (dwarf2Data)
{
if ( !verbose )
- form_value.Dump(s, debug_str_data, cu);
+ form_value.Dump(s, debug_str_data);
DWARFLocationList::Dump(s, cu, dwarf2Data->get_debug_loc_data(), debug_loc_offset);
}
else
{
if ( !verbose )
- form_value.Dump(s, NULL, cu);
+ form_value.Dump(s, NULL);
}
}
}
@@ -1162,8 +1159,8 @@ DWARFDebugInfoEntry::DumpAttribute
case DW_AT_abstract_origin:
case DW_AT_specification:
{
- uint64_t abstract_die_offset = form_value.Reference(cu);
- form_value.Dump(s, debug_str_data, cu);
+ uint64_t abstract_die_offset = form_value.Reference();
+ form_value.Dump(s, debug_str_data);
// *ostrm_ptr << HEX32 << abstract_die_offset << " ( ";
if ( verbose ) s.PutCString(" ( ");
GetName(dwarf2Data, cu, abstract_die_offset, s);
@@ -1173,9 +1170,9 @@ DWARFDebugInfoEntry::DumpAttribute
case DW_AT_type:
{
- uint64_t type_die_offset = form_value.Reference(cu);
+ uint64_t type_die_offset = form_value.Reference();
if (!verbose)
- form_value.Dump(s, debug_str_data, cu);
+ form_value.Dump(s, debug_str_data);
s.PutCString(" ( ");
AppendTypeName(dwarf2Data, cu, type_die_offset, s);
s.PutCString(" )");
@@ -1185,7 +1182,7 @@ DWARFDebugInfoEntry::DumpAttribute
case DW_AT_ranges:
{
if ( !verbose )
- form_value.Dump(s, debug_str_data, cu);
+ form_value.Dump(s, debug_str_data);
lldb::offset_t ranges_offset = form_value.Unsigned();
dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
if (dwarf2Data)
@@ -1195,7 +1192,7 @@ DWARFDebugInfoEntry::DumpAttribute
default:
if ( !verbose )
- form_value.Dump(s, debug_str_data, cu);
+ form_value.Dump(s, debug_str_data);
break;
}
@@ -1226,13 +1223,12 @@ DWARFDebugInfoEntry::GetAttributes
const DWARFDataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
if (fixed_form_sizes == NULL)
- fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize(cu->GetAddressByteSize());
+ fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize(cu->GetAddressByteSize(), cu->IsDWARF64());
const uint32_t num_attributes = abbrevDecl->NumAttributes();
uint32_t i;
dw_attr_t attr;
dw_form_t form;
- DWARFFormValue form_value;
for (i=0; i<num_attributes; ++i)
{
abbrevDecl->GetAttrAndFormByIndexUnchecked (i, attr, form);
@@ -1259,11 +1255,11 @@ DWARFDebugInfoEntry::GetAttributes
if ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin))
{
- form_value.SetForm(form);
- if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ DWARFFormValue form_value (cu, form);
+ if (form_value.ExtractValue(debug_info_data, &offset))
{
const DWARFDebugInfoEntry* die = NULL;
- dw_offset_t die_offset = form_value.Reference(cu);
+ dw_offset_t die_offset = form_value.Reference();
if (cu->ContainsDIEOffset(die_offset))
{
die = const_cast<DWARFCompileUnit*>(cu)->GetDIEPtr(die_offset);
@@ -1331,8 +1327,9 @@ DWARFDebugInfoEntry::GetAttributeValue
DWARFFormValue::SkipValue(abbrevDecl->GetFormByIndex(idx++), debug_info_data, &offset, cu);
const dw_offset_t attr_offset = offset;
+ form_value.SetCompileUnit(cu);
form_value.SetForm(abbrevDecl->GetFormByIndex(idx));
- if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ if (form_value.ExtractValue(debug_info_data, &offset))
{
if (end_attr_offset_ptr)
*end_attr_offset_ptr = offset;
@@ -1423,7 +1420,7 @@ DWARFDebugInfoEntry::GetAttributeValueAsReference
{
DWARFFormValue form_value;
if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
- return form_value.Reference(cu);
+ return form_value.Reference();
return fail_value;
}
@@ -1590,7 +1587,7 @@ DWARFDebugInfoEntry::GetName
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), &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());
}
@@ -1661,7 +1658,7 @@ DWARFDebugInfoEntry::GetPubname
// The specification DIE may be in another compile unit so we need
// to get a die and its compile unit.
DWARFCompileUnitSP cu_sp_ptr;
- const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr);
+ const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(), &cu_sp_ptr);
if (die)
return die->GetPubname(dwarf2Data, cu_sp_ptr.get());
}
@@ -1798,7 +1795,7 @@ DWARFDebugInfoEntry::AppendTypeName
DWARFFormValue form_value;
if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_type, form_value))
{
- uint64_t next_die_offset = form_value.Reference(cu);
+ uint64_t next_die_offset = form_value.Reference();
result = AppendTypeName(dwarf2Data, cu, next_die_offset, s);
}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
index 6a2649463b54..11589aede708 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
@@ -418,12 +418,16 @@ DWARFDebugLine::ParsePrologue(const DWARFDataExtractor& debug_line_data, lldb::o
const char * s;
prologue->total_length = debug_line_data.GetDWARFInitialLength(offset_ptr);
prologue->version = debug_line_data.GetU16(offset_ptr);
- if (prologue->version < 2 || prologue->version > 3)
+ if (prologue->version < 2 || prologue->version > 4)
return false;
prologue->prologue_length = debug_line_data.GetDWARFOffset(offset_ptr);
const lldb::offset_t end_prologue_offset = prologue->prologue_length + *offset_ptr;
prologue->min_inst_length = debug_line_data.GetU8(offset_ptr);
+ if (prologue->version >= 4)
+ prologue->maximum_operations_per_instruction = debug_line_data.GetU8(offset_ptr);
+ else
+ prologue->maximum_operations_per_instruction = 1;
prologue->default_is_stmt = debug_line_data.GetU8(offset_ptr);
prologue->line_base = debug_line_data.GetU8(offset_ptr);
prologue->line_range = debug_line_data.GetU8(offset_ptr);
@@ -486,13 +490,16 @@ DWARFDebugLine::ParseSupportFiles (const lldb::ModuleSP &module_sp,
(void)debug_line_data.GetDWARFInitialLength(&offset);
const char * s;
uint32_t version = debug_line_data.GetU16(&offset);
- if (version < 2 || version > 3)
+ if (version < 2 || version > 4)
return false;
const dw_offset_t end_prologue_offset = debug_line_data.GetDWARFOffset(&offset) + offset;
- // Skip instruction length, default is stmt, line base, line range and
- // opcode base, and all opcode lengths
+ // Skip instruction length, default is stmt, line base, line range
offset += 4;
+ // For DWARF4, skip maximum operations per instruction
+ if (version >= 4)
+ offset += 1;
+ // 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;
@@ -650,7 +657,10 @@ DWARFDebugLine::ParseStatementTable
// relocatable address. All of the other statement program opcodes
// that affect the address register add a delta to it. This instruction
// stores a relocatable value into it instead.
- state.address = debug_line_data.GetAddress(offset_ptr);
+ if (arg_size == 4)
+ state.address = debug_line_data.GetU32(offset_ptr);
+ else // arg_size == 8
+ state.address = debug_line_data.GetU64(offset_ptr);
break;
case DW_LNE_define_file:
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
index 0caaf596add5..7da0e76a22be 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
@@ -75,6 +75,7 @@ public:
uint16_t version; // Version identifier for the statement information format.
uint32_t prologue_length;// The number of bytes following the prologue_length field to the beginning of the first byte of the statement program itself.
uint8_t min_inst_length;// The size in bytes of the smallest target machine instruction. Statement program opcodes that alter the address register first multiply their operands by this value.
+ uint8_t maximum_operations_per_instruction; // New in DWARF4. The maximum number of individual operations that may be encoded in an instruction.
uint8_t default_is_stmt;// The initial value of theis_stmtregister.
int8_t line_base; // This parameter affects the meaning of the special opcodes. See below.
uint8_t line_range; // This parameter affects the meaning of the special opcodes. See below.
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
index 488e9820b6fa..8469b78d0dd5 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
@@ -87,7 +87,7 @@ DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data)
DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
- const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize());
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize(), cu->IsDWARF64());
bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1;
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
index ab8e68ab5516..a8c550e9176f 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -96,36 +96,92 @@ g_form_sizes_addr8[] =
8, // 0x20 DW_FORM_ref_sig8
};
+// Difference with g_form_sizes_addr8:
+// DW_FORM_strp and DW_FORM_sec_offset are 8 instead of 4
+static uint8_t
+g_form_sizes_addr8_dwarf64[] =
+{
+ 0, // 0x00 unused
+ 8, // 0x01 DW_FORM_addr
+ 0, // 0x02 unused
+ 0, // 0x03 DW_FORM_block2
+ 0, // 0x04 DW_FORM_block4
+ 2, // 0x05 DW_FORM_data2
+ 4, // 0x06 DW_FORM_data4
+ 8, // 0x07 DW_FORM_data8
+ 0, // 0x08 DW_FORM_string
+ 0, // 0x09 DW_FORM_block
+ 0, // 0x0a DW_FORM_block1
+ 1, // 0x0b DW_FORM_data1
+ 1, // 0x0c DW_FORM_flag
+ 0, // 0x0d DW_FORM_sdata
+ 8, // 0x0e DW_FORM_strp
+ 0, // 0x0f DW_FORM_udata
+ 0, // 0x10 DW_FORM_ref_addr (addr size for DWARF2 and earlier, 4 bytes for DWARF32, 8 bytes for DWARF32 in DWARF 3 and later
+ 1, // 0x11 DW_FORM_ref1
+ 2, // 0x12 DW_FORM_ref2
+ 4, // 0x13 DW_FORM_ref4
+ 8, // 0x14 DW_FORM_ref8
+ 0, // 0x15 DW_FORM_ref_udata
+ 0, // 0x16 DW_FORM_indirect
+ 8, // 0x17 DW_FORM_sec_offset
+ 0, // 0x18 DW_FORM_exprloc
+ 0, // 0x19 DW_FORM_flag_present
+ 0, // 0x1a
+ 0, // 0x1b
+ 0, // 0x1c
+ 0, // 0x1d
+ 0, // 0x1e
+ 0, // 0x1f
+ 8, // 0x20 DW_FORM_ref_sig8
+};
+
const uint8_t *
-DWARFFormValue::GetFixedFormSizesForAddressSize (uint8_t addr_size)
+DWARFFormValue::GetFixedFormSizesForAddressSize (uint8_t addr_size, bool is_dwarf64)
{
- switch (addr_size)
- {
- case 4: return g_form_sizes_addr4;
- case 8: return g_form_sizes_addr8;
+ if (!is_dwarf64) {
+ switch (addr_size)
+ {
+ case 4: return g_form_sizes_addr4;
+ case 8: return g_form_sizes_addr8;
+ }
+ } else {
+ if (addr_size == 8)
+ return g_form_sizes_addr8_dwarf64;
+ // is_dwarf64 && addr_size == 4 : no provider does this.
}
return NULL;
}
-DWARFFormValue::DWARFFormValue(dw_form_t form) :
+DWARFFormValue::DWARFFormValue() :
+ m_cu (NULL),
+ m_form(0),
+ m_value()
+{
+}
+
+DWARFFormValue::DWARFFormValue(const DWARFCompileUnit* cu, dw_form_t form) :
+ m_cu (cu),
m_form(form),
m_value()
{
}
bool
-DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* offset_ptr, const DWARFCompileUnit* cu)
+DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* offset_ptr)
{
bool indirect = false;
bool is_block = false;
m_value.data = NULL;
+ uint8_t ref_addr_size;
// Read the value for the form into value and follow and DW_FORM_indirect instances we run into
do
{
indirect = false;
switch (m_form)
{
- case DW_FORM_addr: m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu)); break;
+ case DW_FORM_addr: assert(m_cu);
+ m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(m_cu)); break;
case DW_FORM_block2: m_value.value.uval = data.GetU16(offset_ptr); is_block = true; break;
case DW_FORM_block4: m_value.value.uval = data.GetU32(offset_ptr); is_block = true; break;
case DW_FORM_data2: m_value.value.uval = data.GetU16(offset_ptr); break;
@@ -142,15 +198,17 @@ DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* off
case DW_FORM_data1: m_value.value.uval = data.GetU8(offset_ptr); break;
case DW_FORM_flag: m_value.value.uval = data.GetU8(offset_ptr); break;
case DW_FORM_sdata: m_value.value.sval = data.GetSLEB128(offset_ptr); break;
- case DW_FORM_strp: m_value.value.uval = data.GetU32(offset_ptr); break;
+ case DW_FORM_strp: assert(m_cu);
+ m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); break;
// case DW_FORM_APPLE_db_str:
case DW_FORM_udata: m_value.value.uval = data.GetULEB128(offset_ptr); break;
- case DW_FORM_ref_addr:
- if (cu->GetVersion() <= 2)
- m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu));
- else
- m_value.value.uval = data.GetU32(offset_ptr); // 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet
- break;
+ case DW_FORM_ref_addr: assert(m_cu);
+ ref_addr_size = 4;
+ if (m_cu->GetVersion() <= 2)
+ ref_addr_size = m_cu->GetAddressByteSize();
+ else
+ ref_addr_size = m_cu->IsDWARF64() ? 8 : 4;
+ m_value.value.uval = data.GetMaxU64(offset_ptr, ref_addr_size); break;
case DW_FORM_ref1: m_value.value.uval = data.GetU8(offset_ptr); break;
case DW_FORM_ref2: m_value.value.uval = data.GetU16(offset_ptr); break;
case DW_FORM_ref4: m_value.value.uval = data.GetU32(offset_ptr); break;
@@ -161,7 +219,8 @@ DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* off
indirect = true;
break;
- case DW_FORM_sec_offset: m_value.value.uval = data.GetU32(offset_ptr); break;
+ case DW_FORM_sec_offset: assert(m_cu);
+ m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); break;
case DW_FORM_flag_present: m_value.value.uval = 1; break;
case DW_FORM_ref_sig8: m_value.value.uval = data.GetU64(offset_ptr); break;
default:
@@ -183,14 +242,15 @@ DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* off
}
bool
-DWARFFormValue::SkipValue(const DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu) const
+DWARFFormValue::SkipValue(const DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr) const
{
- return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, cu);
+ return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, m_cu);
}
bool
DWARFFormValue::SkipValue(dw_form_t form, const DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu)
{
+ uint8_t ref_addr_size;
switch (form)
{
// Blocks if inlined data that have a length field and the data bytes
@@ -212,10 +272,13 @@ DWARFFormValue::SkipValue(dw_form_t form, const DWARFDataExtractor& debug_info_d
return true;
case DW_FORM_ref_addr:
+ ref_addr_size = 4;
+ assert (cu); // CU must be valid for DW_FORM_ref_addr objects or we will get this wrong
if (cu->GetVersion() <= 2)
- *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu);
+ ref_addr_size = cu->GetAddressByteSize();
else
- *offset_ptr += 4;// 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet
+ ref_addr_size = cu->IsDWARF64() ? 8 : 4;
+ *offset_ptr += ref_addr_size;
return true;
// 0 bytes values (implied from DW_FORM)
@@ -237,11 +300,12 @@ DWARFFormValue::SkipValue(dw_form_t form, const DWARFDataExtractor& debug_info_d
// 32 bit for DWARF 32, 64 for DWARF 64
case DW_FORM_sec_offset:
- *offset_ptr += 4;
+ case DW_FORM_strp:
+ assert(cu);
+ *offset_ptr += (cu->IsDWARF64() ? 8 : 4);
return true;
// 4 byte values
- case DW_FORM_strp:
case DW_FORM_data4:
case DW_FORM_ref4:
*offset_ptr += 4;
@@ -278,7 +342,7 @@ DWARFFormValue::SkipValue(dw_form_t form, const DWARFDataExtractor& debug_info_d
void
-DWARFFormValue::Dump(Stream &s, const DWARFDataExtractor* debug_str_data, const DWARFCompileUnit* cu) const
+DWARFFormValue::Dump(Stream &s, const DWARFDataExtractor* debug_str_data) const
{
uint64_t uvalue = Unsigned();
bool cu_relative_offset = false;
@@ -348,7 +412,8 @@ DWARFFormValue::Dump(Stream &s, const DWARFDataExtractor* debug_str_data, const
case DW_FORM_ref_addr:
{
- if (cu->GetVersion() <= 2)
+ assert (m_cu); // CU must be valid for DW_FORM_ref_addr objects or we will get this wrong
+ if (m_cu->GetVersion() <= 2)
s.Address(uvalue, sizeof (uint64_t) * 2);
else
s.Address(uvalue, 4 * 2);// 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet
@@ -370,10 +435,11 @@ DWARFFormValue::Dump(Stream &s, const DWARFDataExtractor* debug_str_data, const
if (cu_relative_offset)
{
+ assert (m_cu); // CU must be valid for DW_FORM_ref forms that are compile unit relative or we will get this wrong
if (verbose)
s.PutCString(" => ");
- s.Printf("{0x%8.8" PRIx64 "}", (uvalue + (cu ? cu->GetOffset() : 0)));
+ s.Printf("{0x%8.8" PRIx64 "}", uvalue + m_cu->GetOffset());
}
}
@@ -388,7 +454,7 @@ DWARFFormValue::AsCString(const DWARFDataExtractor* debug_str_data_ptr) const
}
uint64_t
-DWARFFormValue::Reference(const DWARFCompileUnit* cu) const
+DWARFFormValue::Reference() const
{
uint64_t die_offset = m_value.value.uval;
switch (m_form)
@@ -398,7 +464,8 @@ DWARFFormValue::Reference(const DWARFCompileUnit* cu) const
case DW_FORM_ref4:
case DW_FORM_ref8:
case DW_FORM_ref_udata:
- die_offset += (cu ? cu->GetOffset() : 0);
+ assert (m_cu); // CU must be valid for DW_FORM_ref forms that are compile unit relative or we will get this wrong
+ die_offset += m_cu->GetOffset();
break;
default:
@@ -429,32 +496,6 @@ DWARFFormValue::Reference (dw_offset_t base_offset) const
return die_offset;
}
-//----------------------------------------------------------------------
-// Resolve any compile unit specific references so that we don't need
-// the compile unit at a later time in order to work with the form
-// value.
-//----------------------------------------------------------------------
-bool
-DWARFFormValue::ResolveCompileUnitReferences(const DWARFCompileUnit* cu)
-{
- switch (m_form)
- {
- case DW_FORM_ref1:
- case DW_FORM_ref2:
- case DW_FORM_ref4:
- case DW_FORM_ref8:
- case DW_FORM_ref_udata:
- m_value.value.uval += cu->GetOffset();
- m_form = DW_FORM_ref_addr;
- return true;
- break;
-
- default:
- break;
- }
-
- return false;
-}
const uint8_t*
DWARFFormValue::BlockData() const
@@ -496,7 +537,7 @@ DWARFFormValue::IsDataForm(const dw_form_t form)
}
int
-DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_value, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const DWARFDataExtractor* debug_str_data_ptr)
+DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_value, const DWARFDataExtractor* debug_str_data_ptr)
{
dw_form_t a_form = a_value.Form();
dw_form_t b_form = b_value.Form();
@@ -577,8 +618,8 @@ DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_
case DW_FORM_ref8:
case DW_FORM_ref_udata:
{
- uint64_t a = a_value.Reference(a_cu);
- uint64_t b = b_value.Reference(b_cu);
+ uint64_t a = a_value.Reference();
+ uint64_t b = b_value.Reference();
if (a < b)
return -1;
if (a > b)
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
index d6c580c7ab1b..392df26a088e 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
+++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
@@ -45,35 +45,34 @@ public:
eValueTypeBlock
};
- DWARFFormValue(dw_form_t form = 0);
+ DWARFFormValue();
+ DWARFFormValue(const DWARFCompileUnit* cu, dw_form_t form);
+ const DWARFCompileUnit* GetCompileUnit () const { return m_cu; }
+ void SetCompileUnit (const DWARFCompileUnit* cu) { m_cu = cu; }
dw_form_t Form() const { return m_form; }
void SetForm(dw_form_t form) { m_form = form; }
const ValueType& Value() const { return m_value; }
- void Dump(lldb_private::Stream &s, const lldb_private::DWARFDataExtractor* debug_str_data, const DWARFCompileUnit* cu) const;
+ void Dump(lldb_private::Stream &s, const lldb_private::DWARFDataExtractor* debug_str_data) const;
bool ExtractValue(const lldb_private::DWARFDataExtractor& data,
- lldb::offset_t* offset_ptr,
- const DWARFCompileUnit* cu);
+ lldb::offset_t* offset_ptr);
bool IsInlinedCStr() const { return (m_value.data != NULL) && m_value.data == (const uint8_t*)m_value.value.cstr; }
const uint8_t* BlockData() const;
- uint64_t Reference(const DWARFCompileUnit* cu) const;
+ uint64_t Reference() const;
uint64_t Reference (dw_offset_t offset) const;
- bool ResolveCompileUnitReferences(const DWARFCompileUnit* cu);
bool Boolean() const { return m_value.value.uval != 0; }
uint64_t Unsigned() const { return m_value.value.uval; }
void SetUnsigned(uint64_t uval) { m_value.value.uval = uval; }
int64_t Signed() const { return m_value.value.sval; }
void SetSigned(int64_t sval) { m_value.value.sval = sval; }
const char* AsCString(const lldb_private::DWARFDataExtractor* debug_str_data_ptr) const;
- bool SkipValue(const lldb_private::DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu) const;
+ bool SkipValue(const lldb_private::DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr) const;
static bool SkipValue(const dw_form_t form, const lldb_private::DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu);
-// static bool TransferValue(dw_form_t form, const lldb_private::DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff);
-// static bool TransferValue(const DWARFFormValue& formValue, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff);
-// static bool PutUnsigned(dw_form_t form, dw_offset_t offset, uint64_t value, BinaryStreamBuf& out_buff, const DWARFCompileUnit* cu, bool fixup_cu_relative_refs);
static bool IsBlockForm(const dw_form_t form);
static bool IsDataForm(const dw_form_t form);
- static const uint8_t * GetFixedFormSizesForAddressSize (uint8_t addr_size);
- static int Compare (const DWARFFormValue& a, const DWARFFormValue& b, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const lldb_private::DWARFDataExtractor* debug_str_data_ptr);
+ static const uint8_t * GetFixedFormSizesForAddressSize (uint8_t addr_size, bool is_dwarf64);
+ static int Compare (const DWARFFormValue& a, const DWARFFormValue& b, const lldb_private::DWARFDataExtractor* debug_str_data_ptr);
protected:
+ const DWARFCompileUnit* m_cu; // Compile unit for this form
dw_form_t m_form; // Form for this value
ValueType m_value; // Contains all data for the form
};
diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
index ab0c37beeac9..f8a8cc60467d 100644
--- a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
+++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
@@ -442,9 +442,9 @@ struct DWARFMappedHash
for (size_t i=0; i<num_atoms; ++i)
{
- DWARFFormValue form_value (header_data.atoms[i].form);
+ DWARFFormValue form_value (NULL, header_data.atoms[i].form);
- if (!form_value.ExtractValue(data, offset_ptr, NULL))
+ if (!form_value.ExtractValue(data, offset_ptr))
return false;
switch (header_data.atoms[i].type)
@@ -481,7 +481,7 @@ struct DWARFMappedHash
if (i > 0)
strm.PutCString (", ");
- DWARFFormValue form_value (header_data.atoms[i].form);
+ DWARFFormValue form_value (NULL, header_data.atoms[i].form);
switch (header_data.atoms[i].type)
{
case eAtomTypeDIEOffset: // DIE offset, check form for encoding
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 842260dbc3ba..b3a5476227f4 100644
--- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -1457,7 +1457,7 @@ SymbolFileDWARF::ParseTemplateDIE (DWARFCompileUnit* dwarf_cu,
case DW_TAG_template_type_parameter:
case DW_TAG_template_value_parameter:
{
- const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize(), dwarf_cu->IsDWARF64());
DWARFDebugInfoEntry::Attributes attributes;
const size_t num_attributes = die->GetAttributes (this,
@@ -1486,7 +1486,7 @@ SymbolFileDWARF::ParseTemplateDIE (DWARFCompileUnit* dwarf_cu,
case DW_AT_type:
if (attributes.ExtractFormValueAtIndex(this, i, form_value))
{
- const dw_offset_t type_die_offset = form_value.Reference(dwarf_cu);
+ const dw_offset_t type_die_offset = form_value.Reference();
lldb_type = ResolveTypeUID(type_die_offset);
if (lldb_type)
clang_type = lldb_type->GetClangForwardType();
@@ -1752,7 +1752,7 @@ SymbolFileDWARF::ParseChildMembers
size_t count = 0;
const DWARFDebugInfoEntry *die;
- const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize(), dwarf_cu->IsDWARF64());
uint32_t member_idx = 0;
BitfieldInfo last_field_info;
ModuleSP module = GetObjectFile()->GetModule();
@@ -1803,7 +1803,7 @@ SymbolFileDWARF::ParseChildMembers
case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break;
- case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_type: encoding_uid = form_value.Reference(); break;
case DW_AT_bit_offset: bit_offset = form_value.Unsigned(); break;
case DW_AT_bit_size: bit_size = form_value.Unsigned(); break;
case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
@@ -2201,7 +2201,7 @@ SymbolFileDWARF::ParseChildMembers
case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
- case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_type: encoding_uid = form_value.Reference(); break;
case DW_AT_data_member_location:
if (form_value.BlockData())
{
@@ -2990,7 +2990,7 @@ SymbolFileDWARF::ResolveSymbolContext(const FileSpec& file_spec, uint32_t line,
if (block_die != NULL)
sc.block = block.FindBlockByID (MakeUserID(block_die->GetOffset()));
- else
+ else if (function_die != NULL)
sc.block = block.FindBlockByID (MakeUserID(function_die->GetOffset()));
}
}
@@ -3033,7 +3033,7 @@ SymbolFileDWARF::Index ()
m_indexed = true;
Timer scoped_timer (__PRETTY_FUNCTION__,
"SymbolFileDWARF::Index (%s)",
- GetObjectFile()->GetFileSpec().GetFilename().AsCString());
+ GetObjectFile()->GetFileSpec().GetFilename().AsCString("<Unknown>"));
DWARFDebugInfo* debug_info = DebugInfo();
if (debug_info)
@@ -3197,13 +3197,13 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat
if (m_apple_names_ap.get())
{
const char *name_cstr = name.GetCString();
- const char *base_name_start;
- const char *base_name_end = NULL;
+ llvm::StringRef basename;
+ llvm::StringRef context;
- if (!CPPLanguageRuntime::StripNamespacesFromVariableName(name_cstr, base_name_start, base_name_end))
- base_name_start = name_cstr;
+ if (!CPPLanguageRuntime::ExtractContextAndIdentifier(name_cstr, context, basename))
+ basename = name_cstr;
- m_apple_names_ap->FindByName (base_name_start, die_offsets);
+ m_apple_names_ap->FindByName (basename.data(), die_offsets);
}
}
else
@@ -3402,7 +3402,7 @@ SymbolFileDWARF::ResolveFunction (DWARFCompileUnit *cu,
break;
}
}
- assert (die->Tag() == DW_TAG_subprogram);
+ assert (die && die->Tag() == DW_TAG_subprogram);
if (GetFunction (cu, die, sc))
{
Address addr;
@@ -4231,7 +4231,7 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc,
if (parent_die == NULL)
return 0;
- const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize(), dwarf_cu->IsDWARF64());
size_t arg_idx = 0;
const DWARFDebugInfoEntry *die;
@@ -4266,7 +4266,7 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc,
case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break;
- case DW_AT_type: param_type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_type: param_type_die_offset = form_value.Reference(); break;
case DW_AT_artificial: is_artificial = form_value.Boolean(); break;
case DW_AT_location:
// if (form_value.BlockData())
@@ -4409,7 +4409,7 @@ SymbolFileDWARF::ParseChildEnumerators
size_t enumerators_added = 0;
const DWARFDebugInfoEntry *die;
- const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize(), dwarf_cu->IsDWARF64());
for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
{
@@ -4488,7 +4488,7 @@ SymbolFileDWARF::ParseChildArrayInfo
return;
const DWARFDebugInfoEntry *die;
- const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize(), dwarf_cu->IsDWARF64());
for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
{
const dw_tag_t tag = die->Tag();
@@ -4929,7 +4929,7 @@ SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry
{
DEBUG_PRINTF ("resolved 0x%8.8" PRIx64 " from %s to 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ")\n",
MakeUserID(die->GetOffset()),
- m_obj_file->GetFileSpec().GetFilename().AsCString(),
+ m_obj_file->GetFileSpec().GetFilename().AsCString("<Unknown>"),
MakeUserID(type_die->GetOffset()),
MakeUserID(type_cu->GetOffset()));
@@ -5060,189 +5060,6 @@ SymbolFileDWARF::DIEDeclContextsMatch (DWARFCompileUnit* cu1, const DWARFDebugIn
return true;
}
-// This function can be used when a DIE is found that is a forward declaration
-// DIE and we want to try and find a type that has the complete definition.
-// "cu" and "die" must be from this SymbolFileDWARF
-TypeSP
-SymbolFileDWARF::FindDefinitionTypeForDIE (DWARFCompileUnit* cu,
- const DWARFDebugInfoEntry *die,
- const ConstString &type_name)
-{
- TypeSP type_sp;
-
-#if defined (LLDB_CONFIGURATION_DEBUG)
- // You can't and shouldn't call this function with a compile unit from
- // another SymbolFileDWARF instance.
- assert (DebugInfo()->ContainsCompileUnit (cu));
-#endif
-
- if (cu == NULL || die == NULL || !type_name)
- return type_sp;
-
- std::string qualified_name;
-
- Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION|DWARF_LOG_LOOKUPS));
- if (log)
- {
- die->GetQualifiedName(this, cu, qualified_name);
- GetObjectFile()->GetModule()->LogMessage (log,
- "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x (%s), name='%s')",
- die->GetOffset(),
- qualified_name.c_str(),
- type_name.GetCString());
- }
-
- DIEArray die_offsets;
-
- if (m_using_apple_tables)
- {
- if (m_apple_types_ap.get())
- {
- const bool has_tag = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeTag);
- const bool has_qualified_name_hash = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeQualNameHash);
- if (has_tag && has_qualified_name_hash)
- {
- if (qualified_name.empty())
- die->GetQualifiedName(this, cu, qualified_name);
-
- const uint32_t qualified_name_hash = MappedHash::HashStringUsingDJB (qualified_name.c_str());
- if (log)
- GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTagAndQualifiedNameHash()");
- m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash (type_name.GetCString(), die->Tag(), qualified_name_hash, die_offsets);
- }
- else if (has_tag)
- {
- if (log)
- GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTag()");
- m_apple_types_ap->FindByNameAndTag (type_name.GetCString(), die->Tag(), die_offsets);
- }
- else
- {
- m_apple_types_ap->FindByName (type_name.GetCString(), die_offsets);
- }
- }
- }
- else
- {
- if (!m_indexed)
- Index ();
-
- m_type_index.Find (type_name, die_offsets);
- }
-
- const size_t num_matches = die_offsets.size();
-
- const dw_tag_t die_tag = die->Tag();
-
- DWARFCompileUnit* type_cu = NULL;
- const DWARFDebugInfoEntry* type_die = NULL;
- if (num_matches)
- {
- DWARFDebugInfo* debug_info = DebugInfo();
- for (size_t i=0; i<num_matches; ++i)
- {
- const dw_offset_t die_offset = die_offsets[i];
- type_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &type_cu);
-
- if (type_die)
- {
- bool try_resolving_type = false;
-
- // Don't try and resolve the DIE we are looking for with the DIE itself!
- if (type_die != die)
- {
- const dw_tag_t type_die_tag = type_die->Tag();
- // Make sure the tags match
- if (type_die_tag == die_tag)
- {
- // The tags match, lets try resolving this type
- try_resolving_type = true;
- }
- else
- {
- // The tags don't match, but we need to watch our for a
- // forward declaration for a struct and ("struct foo")
- // ends up being a class ("class foo { ... };") or
- // vice versa.
- switch (type_die_tag)
- {
- case DW_TAG_class_type:
- // We had a "class foo", see if we ended up with a "struct foo { ... };"
- try_resolving_type = (die_tag == DW_TAG_structure_type);
- break;
- case DW_TAG_structure_type:
- // We had a "struct foo", see if we ended up with a "class foo { ... };"
- try_resolving_type = (die_tag == DW_TAG_class_type);
- break;
- default:
- // Tags don't match, don't event try to resolve
- // using this type whose name matches....
- break;
- }
- }
- }
-
- if (try_resolving_type)
- {
- if (log)
- {
- std::string qualified_name;
- type_die->GetQualifiedName(this, cu, qualified_name);
- GetObjectFile()->GetModule()->LogMessage (log,
- "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x, name='%s') trying die=0x%8.8x (%s)",
- die->GetOffset(),
- type_name.GetCString(),
- type_die->GetOffset(),
- qualified_name.c_str());
- }
-
- // Make sure the decl contexts match all the way up
- if (DIEDeclContextsMatch(cu, die, type_cu, type_die))
- {
- Type *resolved_type = ResolveType (type_cu, type_die, false);
- if (resolved_type && resolved_type != DIE_IS_BEING_PARSED)
- {
- DEBUG_PRINTF ("resolved 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ") from %s to 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ")\n",
- MakeUserID(die->GetOffset()),
- MakeUserID(cu->GetOffset()),
- m_obj_file->GetFileSpec().GetFilename().AsCString(),
- MakeUserID(type_die->GetOffset()),
- MakeUserID(type_cu->GetOffset()));
-
- m_die_to_type[die] = resolved_type;
- type_sp = resolved_type->shared_from_this();
- break;
- }
- }
- }
- else
- {
- if (log)
- {
- std::string qualified_name;
- type_die->GetQualifiedName(this, cu, qualified_name);
- GetObjectFile()->GetModule()->LogMessage (log,
- "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x, name='%s') ignoring die=0x%8.8x (%s)",
- die->GetOffset(),
- type_name.GetCString(),
- type_die->GetOffset(),
- qualified_name.c_str());
- }
- }
- }
- else
- {
- if (m_using_apple_tables)
- {
- GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n",
- die_offset, type_name.GetCString());
- }
- }
-
- }
- }
- return type_sp;
-}
TypeSP
SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &dwarf_decl_ctx)
@@ -5828,7 +5645,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
break;
case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
case DW_AT_encoding: encoding = form_value.Unsigned(); break;
- case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_type: encoding_uid = form_value.Reference(); break;
default:
case DW_AT_sibling:
break;
@@ -6403,7 +6220,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
type_name_cstr = form_value.AsCString(&get_debug_str_data());
type_name_const_str.SetCString(type_name_cstr);
break;
- case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_type: encoding_uid = form_value.Reference(); break;
case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
case DW_AT_accessibility: break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break;
case DW_AT_declaration: break; //is_forward_declaration = form_value.Boolean(); break;
@@ -6521,7 +6338,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name: break; // mangled = form_value.AsCString(&get_debug_str_data()); break;
- case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_type: type_die_offset = form_value.Reference(); break;
case DW_AT_accessibility: accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break;
case DW_AT_declaration: break; // is_forward_declaration = form_value.Boolean(); break;
case DW_AT_inline: is_inline = form_value.Boolean(); break;
@@ -6541,15 +6358,15 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
break;
case DW_AT_specification:
- specification_die_offset = form_value.Reference(dwarf_cu);
+ specification_die_offset = form_value.Reference();
break;
case DW_AT_abstract_origin:
- abstract_origin_die_offset = form_value.Reference(dwarf_cu);
+ abstract_origin_die_offset = form_value.Reference();
break;
case DW_AT_object_pointer:
- object_pointer_die_offset = form_value.Reference(dwarf_cu);
+ object_pointer_die_offset = form_value.Reference();
break;
case DW_AT_allocated:
@@ -6985,7 +6802,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
type_name_const_str.SetCString(type_name_cstr);
break;
- case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_type: type_die_offset = form_value.Reference(); break;
case DW_AT_byte_size: break; // byte_size = form_value.Unsigned(); break;
case DW_AT_byte_stride: byte_stride = form_value.Unsigned(); break;
case DW_AT_bit_stride: bit_stride = form_value.Unsigned(); break;
@@ -7019,17 +6836,26 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
byte_stride = element_type->GetByteSize();
ClangASTType array_element_type = element_type->GetClangForwardType();
uint64_t array_element_bit_stride = byte_stride * 8 + bit_stride;
- uint64_t num_elements = 0;
- std::vector<uint64_t>::const_reverse_iterator pos;
- std::vector<uint64_t>::const_reverse_iterator end = element_orders.rend();
- for (pos = element_orders.rbegin(); pos != end; ++pos)
+ if (element_orders.size() > 0)
+ {
+ uint64_t num_elements = 0;
+ std::vector<uint64_t>::const_reverse_iterator pos;
+ std::vector<uint64_t>::const_reverse_iterator end = element_orders.rend();
+ for (pos = element_orders.rbegin(); pos != end; ++pos)
+ {
+ num_elements = *pos;
+ clang_type = ast.CreateArrayType (array_element_type,
+ num_elements,
+ is_vector);
+ array_element_type = clang_type;
+ array_element_bit_stride = num_elements ?
+ array_element_bit_stride * num_elements :
+ array_element_bit_stride;
+ }
+ }
+ else
{
- num_elements = *pos;
- clang_type = ast.CreateArrayType (array_element_type,
- num_elements,
- is_vector);
- array_element_type = clang_type;
- array_element_bit_stride = num_elements ? array_element_bit_stride * num_elements : array_element_bit_stride;
+ clang_type = ast.CreateArrayType (array_element_type, 0, is_vector);
}
ConstString empty_name;
type_sp.reset( new Type (MakeUserID(die->GetOffset()),
@@ -7065,9 +6891,9 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
switch (attr)
{
case DW_AT_type:
- type_die_offset = form_value.Reference(dwarf_cu); break;
+ type_die_offset = form_value.Reference(); break;
case DW_AT_containing_type:
- containing_type_die_offset = form_value.Reference(dwarf_cu); break;
+ containing_type_die_offset = form_value.Reference(); break;
}
}
}
@@ -7114,7 +6940,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
{
symbol_context_scope = sc.comp_unit;
}
- else if (sc.function != NULL)
+ else if (sc.function != NULL && sc_parent_die)
{
symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset()));
if (symbol_context_scope == NULL)
@@ -7347,7 +7173,6 @@ SymbolFileDWARF::ParseVariableDIE
const lldb::addr_t func_low_pc
)
{
-
VariableSP var_sp (m_die_to_variable_sp[die]);
if (var_sp)
return var_sp; // Already been parsed!
@@ -7380,6 +7205,7 @@ SymbolFileDWARF::ParseVariableDIE
{
dw_attr_t attr = attributes.AttributeAtIndex(i);
DWARFFormValue form_value;
+
if (attributes.ExtractFormValueAtIndex(this, i, form_value))
{
switch (attr)
@@ -7390,7 +7216,7 @@ SymbolFileDWARF::ParseVariableDIE
case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break;
case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name: mangled = form_value.AsCString(&get_debug_str_data()); break;
- case DW_AT_type: type_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_type: type_uid = form_value.Reference(); break;
case DW_AT_external: is_external = form_value.Boolean(); break;
case DW_AT_const_value:
// If we have already found a DW_AT_location attribute, ignore this attribute.
@@ -7409,7 +7235,7 @@ SymbolFileDWARF::ParseVariableDIE
else if (DWARFFormValue::IsDataForm(form_value.Form()))
{
// Retrieve the value as a data expression.
- const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (attributes.CompileUnitAtIndex(i)->GetAddressByteSize(), attributes.CompileUnitAtIndex(i)->IsDWARF64());
uint32_t data_offset = attributes.DIEOffsetAtIndex(i);
uint32_t data_length = fixed_form_sizes[form_value.Form()];
if (data_length == 0)
@@ -7417,7 +7243,7 @@ SymbolFileDWARF::ParseVariableDIE
const uint8_t *data_pointer = form_value.BlockData();
if (data_pointer)
{
- data_length = form_value.Unsigned();
+ form_value.Unsigned();
}
else if (DWARFFormValue::IsDataForm(form_value.Form()))
{
@@ -7433,7 +7259,7 @@ SymbolFileDWARF::ParseVariableDIE
// Retrieve the value as a string expression.
if (form_value.Form() == DW_FORM_strp)
{
- const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (attributes.CompileUnitAtIndex(i)->GetAddressByteSize(), attributes.CompileUnitAtIndex(i)->IsDWARF64());
uint32_t data_offset = attributes.DIEOffsetAtIndex(i);
uint32_t data_length = fixed_form_sizes[form_value.Form()];
location.CopyOpcodeData(module, debug_info_data, data_offset, data_length);
@@ -7470,7 +7296,7 @@ SymbolFileDWARF::ParseVariableDIE
{
location.CopyOpcodeData(module, debug_loc_data, debug_loc_offset, loc_list_length);
assert (func_low_pc != LLDB_INVALID_ADDRESS);
- location.SetLocationListSlide (func_low_pc - dwarf_cu->GetBaseAddress());
+ location.SetLocationListSlide (func_low_pc - attributes.CompileUnitAtIndex(i)->GetBaseAddress());
}
}
}
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 178e5142d94b..230e1a5d3984 100644
--- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -421,11 +421,6 @@ protected:
const DWARFMappedHash::MemoryTable &memory_table,
lldb_private::SymbolContextList& sc_list);
- lldb::TypeSP FindDefinitionTypeForDIE (
- DWARFCompileUnit* dwarf_cu,
- const DWARFDebugInfoEntry *die,
- const lldb_private::ConstString &type_name);
-
lldb::TypeSP FindDefinitionTypeForDWARFDeclContext (
const DWARFDeclContext &die_decl_ctx);
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
index b8d56d3909e9..7e484bd8dc73 100644
--- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -146,7 +146,8 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
if (log && log->GetVerbose ())
{
StreamString strm;
- inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL);
+ const char *disassemble_format = "${frame.pc}: ";
+ inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL, NULL, NULL, disassemble_format);
log->PutCString (strm.GetData());
}
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
index 32a21d2b8bb8..dbf37d8a4de0 100644
--- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -23,6 +23,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnwindAssembly.h"
+#include "lldb/Utility/RegisterNumber.h"
using namespace lldb;
using namespace lldb_private;
@@ -318,7 +319,8 @@ AssemblyParse_x86::nonvolatile_reg_p (int machine_regno)
#define REX_W_DSTREG(opcode) ((opcode) & 0x1)
// pushq %rbp [0x55]
-bool AssemblyParse_x86::push_rbp_pattern_p ()
+bool
+AssemblyParse_x86::push_rbp_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
if (*p == 0x55)
@@ -327,7 +329,8 @@ bool AssemblyParse_x86::push_rbp_pattern_p ()
}
// pushq $0 ; the first instruction in start() [0x6a 0x00]
-bool AssemblyParse_x86::push_0_pattern_p ()
+bool
+AssemblyParse_x86::push_0_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
if (*p == 0x6a && *(p + 1) == 0x0)
@@ -337,7 +340,8 @@ bool AssemblyParse_x86::push_0_pattern_p ()
// pushq $0
// pushl $0
-bool AssemblyParse_x86::push_imm_pattern_p ()
+bool
+AssemblyParse_x86::push_imm_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
if (*p == 0x68 || *p == 0x6a)
@@ -347,7 +351,8 @@ bool AssemblyParse_x86::push_imm_pattern_p ()
// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]
// movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]
-bool AssemblyParse_x86::mov_rsp_rbp_pattern_p ()
+bool
+AssemblyParse_x86::mov_rsp_rbp_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
if (m_wordsize == 8 && *p == 0x48)
@@ -360,7 +365,8 @@ bool AssemblyParse_x86::mov_rsp_rbp_pattern_p ()
}
// subq $0x20, %rsp
-bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount)
+bool
+AssemblyParse_x86::sub_rsp_pattern_p (int& amount)
{
uint8_t *p = m_cur_insn_bytes;
if (m_wordsize == 8 && *p == 0x48)
@@ -381,7 +387,8 @@ bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount)
}
// addq $0x20, %rsp
-bool AssemblyParse_x86::add_rsp_pattern_p (int& amount)
+bool
+AssemblyParse_x86::add_rsp_pattern_p (int& amount)
{
uint8_t *p = m_cur_insn_bytes;
if (m_wordsize == 8 && *p == 0x48)
@@ -403,7 +410,8 @@ bool AssemblyParse_x86::add_rsp_pattern_p (int& amount)
// pushq %rbx
// pushl %ebx
-bool AssemblyParse_x86::push_reg_p (int& regno)
+bool
+AssemblyParse_x86::push_reg_p (int& regno)
{
uint8_t *p = m_cur_insn_bytes;
int regno_prefix_bit = 0;
@@ -423,7 +431,8 @@ bool AssemblyParse_x86::push_reg_p (int& regno)
// popq %rbx
// popl %ebx
-bool AssemblyParse_x86::pop_reg_p (int& regno)
+bool
+AssemblyParse_x86::pop_reg_p (int& regno)
{
uint8_t *p = m_cur_insn_bytes;
int regno_prefix_bit = 0;
@@ -443,14 +452,16 @@ bool AssemblyParse_x86::pop_reg_p (int& regno)
// popq %rbp [0x5d]
// popl %ebp [0x5d]
-bool AssemblyParse_x86::pop_rbp_pattern_p ()
+bool
+AssemblyParse_x86::pop_rbp_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
return (*p == 0x5d);
}
// call $0 [0xe8 0x0 0x0 0x0 0x0]
-bool AssemblyParse_x86::call_next_insn_pattern_p ()
+bool
+AssemblyParse_x86::call_next_insn_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
return (*p == 0xe8) && (*(p+1) == 0x0) && (*(p+2) == 0x0)
@@ -468,7 +479,8 @@ bool AssemblyParse_x86::call_next_insn_pattern_p ()
// the actual location. The positive value returned for the offset
// is a convention used elsewhere for CFA offsets et al.
-bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset)
+bool
+AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset)
{
uint8_t *p = m_cur_insn_bytes;
int src_reg_prefix_bit = 0;
@@ -602,7 +614,6 @@ bool
AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
{
UnwindPlan::RowSP row(new UnwindPlan::Row);
- int non_prologue_insn_count = 0;
m_cur_insn = m_func_bounds.GetBaseAddress ();
int current_func_text_offset = 0;
int current_sp_bytes_offset_from_cfa = 0;
@@ -638,20 +649,38 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
*newrow = *row.get();
row.reset(newrow);
+ // Track which registers have been saved so far in the prologue.
+ // If we see another push of that register, it's not part of the prologue.
+ // The register numbers used here are the machine register #'s
+ // (i386_register_numbers, x86_64_register_numbers).
+ std::vector<bool> saved_registers(32, false);
+
const bool prefer_file_cache = true;
+ // Once the prologue has completed we'll save a copy of the unwind instructions
+ // If there is an epilogue in the middle of the function, after that epilogue we'll reinstate
+ // the unwind setup -- we assume that some code path jumps over the mid-function epilogue
+
+ UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
+ int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the epilogue started executed
+ std::vector<bool> prologue_completed_saved_registers;
+
Target *target = m_exe_ctx.GetTargetPtr();
- while (m_func_bounds.ContainsFileAddress (m_cur_insn) && non_prologue_insn_count < 10)
+ while (m_func_bounds.ContainsFileAddress (m_cur_insn))
{
int stack_offset, insn_len;
int machine_regno; // register numbers masked directly out of instructions
uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB numbering scheme
+ bool in_epilogue = false; // we're in the middle of an epilogue sequence
+ bool row_updated = false; // The UnwindPlan::Row 'row' has been updated
+
if (!instruction_length (m_cur_insn, insn_len) || insn_len == 0 || insn_len > kMaxInstructionByteSize)
{
// An unrecognized/junk instruction
break;
}
+
if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
insn_len, error) == static_cast<size_t>(-1))
{
@@ -661,216 +690,193 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
if (push_rbp_pattern_p ())
{
- row->SetOffset (current_func_text_offset + insn_len);
current_sp_bytes_offset_from_cfa += m_wordsize;
row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
UnwindPlan::Row::RegisterLocation regloc;
regloc.SetAtCFAPlusOffset (-row->GetCFAOffset());
row->SetRegisterInfo (m_lldb_fp_regnum, regloc);
- unwind_plan.AppendRow (row);
- // Allocate a new Row, populate it with the existing Row contents.
- newrow = new UnwindPlan::Row;
- *newrow = *row.get();
- row.reset(newrow);
- goto loopnext;
+ saved_registers[m_machine_fp_regnum] = true;
+ row_updated = true;
}
- if (mov_rsp_rbp_pattern_p ())
+ else if (mov_rsp_rbp_pattern_p ())
{
- row->SetOffset (current_func_text_offset + insn_len);
row->SetCFARegister (m_lldb_fp_regnum);
- unwind_plan.AppendRow (row);
- // Allocate a new Row, populate it with the existing Row contents.
- newrow = new UnwindPlan::Row;
- *newrow = *row.get();
- row.reset(newrow);
- goto loopnext;
+ row_updated = true;
}
// This is the start() function (or a pthread equivalent), it starts with a pushl $0x0 which puts the
// saved pc value of 0 on the stack. In this case we want to pretend we didn't see a stack movement at all --
// normally the saved pc value is already on the stack by the time the function starts executing.
- if (push_0_pattern_p ())
+ else if (push_0_pattern_p ())
{
- goto loopnext;
}
- if (push_reg_p (machine_regno))
+ else if (push_reg_p (machine_regno))
{
current_sp_bytes_offset_from_cfa += m_wordsize;
- bool need_to_push_row = false;
// 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)
{
- need_to_push_row = true;
row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row_updated = true;
}
// record where non-volatile (callee-saved, spilled) registers are saved on the stack
- if (nonvolatile_reg_p (machine_regno) && machine_regno_to_lldb_regno (machine_regno, lldb_regno))
+ if (nonvolatile_reg_p (machine_regno)
+ && machine_regno_to_lldb_regno (machine_regno, lldb_regno)
+ && saved_registers[machine_regno] == false)
{
- need_to_push_row = true;
UnwindPlan::Row::RegisterLocation regloc;
regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa);
row->SetRegisterInfo (lldb_regno, regloc);
+ saved_registers[machine_regno] = true;
+ row_updated = true;
}
- if (need_to_push_row)
- {
- row->SetOffset (current_func_text_offset + insn_len);
- unwind_plan.AppendRow (row);
- // Allocate a new Row, populate it with the existing Row contents.
- newrow = new UnwindPlan::Row;
- *newrow = *row.get();
- row.reset(newrow);
- }
- goto loopnext;
}
- if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset) && nonvolatile_reg_p (machine_regno))
+ else if (pop_reg_p (machine_regno))
{
- if (machine_regno_to_lldb_regno (machine_regno, lldb_regno))
+ current_sp_bytes_offset_from_cfa -= m_wordsize;
+
+ if (nonvolatile_reg_p (machine_regno)
+ && machine_regno_to_lldb_regno (machine_regno, lldb_regno)
+ && saved_registers[machine_regno] == true)
{
- row->SetOffset (current_func_text_offset + insn_len);
- UnwindPlan::Row::RegisterLocation regloc;
+ saved_registers[machine_regno] = false;
+ row->RemoveRegisterInfo (lldb_regno);
- // stack_offset for 'movq %r15, -80(%rbp)' will be 80.
- // In the Row, we want to express this as the offset from the CFA. If the frame base
- // is rbp (like the above instruction), the CFA offset for rbp is probably 16. So we
- // want to say that the value is stored at the CFA address - 96.
- regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset()));
+ if (machine_regno == m_machine_fp_regnum)
+ {
+ row->SetCFARegister (m_lldb_sp_regnum);
+ }
- row->SetRegisterInfo (lldb_regno, regloc);
- unwind_plan.AppendRow (row);
- // Allocate a new Row, populate it with the existing Row contents.
- newrow = new UnwindPlan::Row;
- *newrow = *row.get();
- row.reset(newrow);
- goto loopnext;
+ in_epilogue = true;
+ row_updated = true;
}
- }
- if (sub_rsp_pattern_p (stack_offset))
- {
- current_sp_bytes_offset_from_cfa += stack_offset;
+ // 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)
{
- row->SetOffset (current_func_text_offset + insn_len);
row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
- unwind_plan.AppendRow (row);
- // Allocate a new Row, populate it with the existing Row contents.
- newrow = new UnwindPlan::Row;
- *newrow = *row.get();
- row.reset(newrow);
+ row_updated = true;
}
- goto loopnext;
}
- if (ret_pattern_p ())
+ else if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset)
+ && nonvolatile_reg_p (machine_regno)
+ && machine_regno_to_lldb_regno (machine_regno, lldb_regno)
+ && saved_registers[machine_regno] == false)
{
- // we know where the end of the function is; set the limit on the PlanValidAddressRange
- // in case our initial "high pc" value was overly large
- // int original_size = m_func_bounds.GetByteSize();
- // int calculated_size = m_cur_insn.GetOffset() - m_func_bounds.GetBaseAddress().GetOffset() + insn_len + 1;
- // m_func_bounds.SetByteSize (calculated_size);
- // unwind_plan.SetPlanValidAddressRange (m_func_bounds);
- break;
- }
+ saved_registers[machine_regno] = true;
- // FIXME recognize the i386 picbase setup instruction sequence,
- // 0x1f16: call 0x1f1b ; main + 11 at /private/tmp/a.c:3
- // 0x1f1b: popl %eax
- // and record the temporary stack movements if the CFA is not expressed in terms of ebp.
+ UnwindPlan::Row::RegisterLocation regloc;
- non_prologue_insn_count++;
-loopnext:
- m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
- current_func_text_offset += insn_len;
- }
+ // stack_offset for 'movq %r15, -80(%rbp)' will be 80.
+ // In the Row, we want to express this as the offset from the CFA. If the frame base
+ // is rbp (like the above instruction), the CFA offset for rbp is probably 16. So we
+ // want to say that the value is stored at the CFA address - 96.
+ regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset()));
- // Now look at the byte at the end of the AddressRange for a limited attempt at describing the
- // epilogue. We're looking for the sequence
+ row->SetRegisterInfo (lldb_regno, regloc);
- // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
- // [ 0xc3 ] ret
+ row_updated = true;
+ }
- // or
+ else if (sub_rsp_pattern_p (stack_offset))
+ {
+ current_sp_bytes_offset_from_cfa += stack_offset;
+ if (row->GetCFARegister() == m_lldb_sp_regnum)
+ {
+ row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row_updated = true;
+ }
+ }
- // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
- // [ 0xe9 xx xx xx xx ] jmp objc_retainAutoreleaseReturnValue (this is sometimes the final insn in the function)
+ else if (add_rsp_pattern_p (stack_offset))
+ {
+ current_sp_bytes_offset_from_cfa -= stack_offset;
+ if (row->GetCFARegister() == m_lldb_sp_regnum)
+ {
+ row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row_updated = true;
+ }
+ in_epilogue = true;
+ }
- // or
+ else if (ret_pattern_p () && prologue_completed_row.get())
+ {
+ // Reinstate the saved prologue setup for any instructions
+ // that come after the ret instruction
- // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
- // [ 0xc3 ] ret
- // [ 0xe8 xx xx xx xx ] call __stack_chk_fail (this is sometimes the final insn in the function)
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *prologue_completed_row.get();
+ row.reset (newrow);
+ current_sp_bytes_offset_from_cfa = prologue_completed_sp_bytes_offset_from_cfa;
- // We want to add a Row describing how to unwind when we're stopped on the 'ret' instruction where the
- // CFA is no longer defined in terms of rbp, but is now defined in terms of rsp like on function entry.
- // (or the 'jmp' instruction in the second case)
+ saved_registers.clear();
+ saved_registers.resize(prologue_completed_saved_registers.size(), false);
+ for (size_t i = 0; i < prologue_completed_saved_registers.size(); ++i)
+ {
+ saved_registers[i] = prologue_completed_saved_registers[i];
+ }
- uint64_t ret_insn_offset = LLDB_INVALID_ADDRESS;
- Address end_of_fun(m_func_bounds.GetBaseAddress());
- end_of_fun.SetOffset (end_of_fun.GetOffset() + m_func_bounds.GetByteSize());
+ in_epilogue = true;
+ row_updated = true;
+ }
- if (m_func_bounds.GetByteSize() > 7)
- {
- uint8_t bytebuf[7];
- Address last_seven_bytes(end_of_fun);
- last_seven_bytes.SetOffset (last_seven_bytes.GetOffset() - 7);
- if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7,
- error) != static_cast<size_t>(-1))
+ // call next instruction
+ // call 0
+ // => pop %ebx
+ // This is used in i386 programs to get the PIC base address for finding global data
+ else if (call_next_insn_pattern_p ())
{
- if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov & ret
- {
- ret_insn_offset = m_func_bounds.GetByteSize() - 1;
- }
- else if (bytebuf[1] == 0x5d && bytebuf[2] == 0xe9) // mov & jmp
- {
- // When the pc is sitting on the 'jmp' instruction, we have the same
- // unwind state as if it was sitting on a 'ret' instruction.
- ret_insn_offset = m_func_bounds.GetByteSize() - 5;
- }
- else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov & ret & call
+ current_sp_bytes_offset_from_cfa += m_wordsize;
+ if (row->GetCFARegister() == m_lldb_sp_regnum)
{
- ret_insn_offset = m_func_bounds.GetByteSize() - 6;
+ row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row_updated = true;
}
}
- }
- else if (m_func_bounds.GetByteSize() > 2)
- {
- uint8_t bytebuf[2];
- Address last_two_bytes(end_of_fun);
- last_two_bytes.SetOffset (last_two_bytes.GetOffset() - 2);
- if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2,
- error) != static_cast<size_t>(-1))
+
+ if (row_updated)
{
- if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov & ret
+ if (current_func_text_offset + insn_len < m_func_bounds.GetByteSize())
{
- ret_insn_offset = m_func_bounds.GetByteSize() - 1;
+ row->SetOffset (current_func_text_offset + insn_len);
+ unwind_plan.AppendRow (row);
+ // Allocate a new Row, populate it with the existing Row contents.
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
}
}
- }
- if (ret_insn_offset != LLDB_INVALID_ADDRESS)
- {
- // Create a fresh, empty Row and RegisterLocation - don't mention any other registers
- UnwindPlan::RowSP epi_row(new UnwindPlan::Row);
- UnwindPlan::Row::RegisterLocation epi_regloc;
-
- // When the ret instruction is about to be executed, here's our state
- epi_row->SetOffset (ret_insn_offset);
- epi_row->SetCFARegister (m_lldb_sp_regnum);
- epi_row->SetCFAOffset (m_wordsize);
+ if (in_epilogue == false && row_updated)
+ {
+ // If we're not in an epilogue sequence, save the updated Row
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ prologue_completed_row.reset (newrow);
- // caller's stack pointer value before the call insn is the CFA address
- epi_regloc.SetIsCFAPlusOffset (0);
- epi_row->SetRegisterInfo (m_lldb_sp_regnum, epi_regloc);
+ prologue_completed_saved_registers.clear();
+ prologue_completed_saved_registers.resize(saved_registers.size(), false);
+ for (size_t i = 0; i < saved_registers.size(); ++i)
+ {
+ prologue_completed_saved_registers[i] = saved_registers[i];
+ }
+ }
- // saved instruction pointer can be found at CFA - wordsize
- epi_regloc.SetAtCFAPlusOffset (-m_wordsize);
- epi_row->SetRegisterInfo (m_lldb_ip_regnum, epi_regloc);
+ // We may change the sp value without adding a new Row necessarily -- keep
+ // track of it either way.
+ if (in_epilogue == false)
+ {
+ prologue_completed_sp_bytes_offset_from_cfa = current_sp_bytes_offset_from_cfa;
+ }
- unwind_plan.AppendRow (epi_row);
+ m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
+ current_func_text_offset += insn_len;
}
unwind_plan.SetSourceName ("assembly insn profiling");
@@ -902,12 +908,20 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAOffset() != m_wordsize)
return false;
+ UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset (-1);
+
Target *target = m_exe_ctx.GetTargetPtr();
m_cur_insn = func.GetBaseAddress();
uint64_t offset = 0;
int row_id = 1;
bool unwind_plan_updated = false;
UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));
+
+ // After a mid-function epilogue we will need to re-insert the original unwind rules
+ // so unwinds work for the remainder of the function. These aren't common with clang/gcc
+ // on x86 but it is possible.
+ bool reinstate_unwind_state = false;
+
while (func.ContainsFileAddress (m_cur_insn))
{
int insn_len;
@@ -930,10 +944,29 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
offset += insn_len;
m_cur_insn.SetOffset(m_cur_insn.GetOffset() + insn_len);
+ if (reinstate_unwind_state)
+ {
+ // that was the last instruction of this function
+ if (func.ContainsFileAddress (m_cur_insn) == false)
+ continue;
+
+ UnwindPlan::RowSP new_row(new UnwindPlan::Row());
+ *new_row = *original_last_row;
+ new_row->SetOffset (offset);
+ unwind_plan.AppendRow (new_row);
+ row.reset (new UnwindPlan::Row());
+ *row = *new_row;
+ reinstate_unwind_state = false;
+ unwind_plan_updated = true;
+ continue;
+ }
+
// If we already have one row for this instruction, we can continue.
while (row_id < unwind_plan.GetRowCount()
&& unwind_plan.GetRowAtIndex (row_id)->GetOffset() <= offset)
+ {
row_id++;
+ }
UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex (row_id - 1);
if (original_row->GetOffset() == offset)
{
@@ -1032,6 +1065,11 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
unwind_plan_updated = true;
continue;
}
+ if (ret_pattern_p ())
+ {
+ reinstate_unwind_state = true;
+ continue;
+ }
}
else if (cfa_reg == m_lldb_fp_regnum)
{
@@ -1053,6 +1091,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
unwind_plan_updated = true;
+ reinstate_unwind_state = true;
continue;
}
}
@@ -1074,6 +1113,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
unwind_plan_source += " plus augmentation from assembly parsing";
unwind_plan.SetSourceName (unwind_plan_source.c_str());
unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
}
return true;
}
@@ -1239,17 +1279,130 @@ UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& func, Th
bool
UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
{
- ExecutionContext exe_ctx (thread.shared_from_this());
- AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
- return asm_parse.augment_unwind_plan_from_call_site (func, unwind_plan);
+ bool do_augment_unwindplan = true;
+
+ UnwindPlan::RowSP first_row = unwind_plan.GetRowForFunctionOffset (0);
+ UnwindPlan::RowSP last_row = unwind_plan.GetRowForFunctionOffset (-1);
+
+ int wordsize = 8;
+ ProcessSP process_sp (thread.GetProcess());
+ if (process_sp)
+ {
+ wordsize = process_sp->GetTarget().GetArchitecture().GetAddressByteSize();
+ }
+
+ RegisterNumber sp_regnum (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ RegisterNumber pc_regnum (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+
+ // Does this UnwindPlan describe the prologue? I want to see that the CFA is set
+ // in terms of the stack pointer plus an offset, and I want to see that rip is
+ // retrieved at the CFA-wordsize.
+ // 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)
+ {
+ return false;
+ }
+ UnwindPlan::Row::RegisterLocation first_row_pc_loc;
+ if (first_row->GetRegisterInfo (pc_regnum.GetAsKind (unwind_plan.GetRegisterKind()), first_row_pc_loc) == false
+ || first_row_pc_loc.IsAtCFAPlusOffset() == false
+ || first_row_pc_loc.GetOffset() != -wordsize)
+ {
+ return false;
+ }
+
+
+ // It looks like the prologue is described.
+ // Is the epilogue described? If it is, no need to do any augmentation.
+
+ if (first_row != last_row && first_row->GetOffset() != last_row->GetOffset())
+ {
+ // The first & last row have the same CFA register
+ // and the same CFA offset value
+ // and the CFA register is esp/rsp (the stack pointer).
+
+ // 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())
+ {
+ // Get the register locations for eip/rip from the first & last rows.
+ // Are they both CFA plus an offset? Is it the same offset?
+
+ UnwindPlan::Row::RegisterLocation last_row_pc_loc;
+ if (last_row->GetRegisterInfo (pc_regnum.GetAsKind (unwind_plan.GetRegisterKind()), last_row_pc_loc))
+ {
+ if (last_row_pc_loc.IsAtCFAPlusOffset()
+ && first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset())
+ {
+
+ // One last sanity check: Is the unwind rule for getting the caller pc value
+ // "deref the CFA-4" or "deref the CFA-8"?
+
+ // If so, we have an UnwindPlan that already describes the epilogue and we don't need
+ // to modify it at all.
+
+ if (first_row_pc_loc.GetOffset() == -wordsize)
+ {
+ do_augment_unwindplan = false;
+ }
+ }
+ }
+ }
+ }
+
+ if (do_augment_unwindplan)
+ {
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
+ return asm_parse.augment_unwind_plan_from_call_site (func, unwind_plan);
+ }
+
+ return false;
}
bool
UnwindAssembly_x86::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan)
{
- ExecutionContext exe_ctx (thread.shared_from_this());
- AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
- return asm_parse.get_fast_unwind_plan (func, unwind_plan);
+ // if prologue is
+ // 55 pushl %ebp
+ // 89 e5 movl %esp, %ebp
+ // or
+ // 55 pushq %rbp
+ // 48 89 e5 movq %rsp, %rbp
+
+ // We should pull in the ABI architecture default unwind plan and return that
+
+ llvm::SmallVector <uint8_t, 4> opcode_data;
+
+ ProcessSP process_sp = thread.GetProcess();
+ if (process_sp)
+ {
+ Target &target (process_sp->GetTarget());
+ const bool prefer_file_cache = true;
+ Error error;
+ if (target.ReadMemory (func.GetBaseAddress (), prefer_file_cache, opcode_data.data(),
+ 4, error) == 4)
+ {
+ uint8_t i386_push_mov[] = {0x55, 0x89, 0xe5};
+ uint8_t x86_64_push_mov[] = {0x55, 0x48, 0x89, 0xe5};
+
+ if (memcmp (opcode_data.data(), i386_push_mov, sizeof (i386_push_mov)) == 0
+ || memcmp (opcode_data.data(), x86_64_push_mov, sizeof (x86_64_push_mov)) == 0)
+ {
+ ABISP abi_sp = process_sp->GetABI();
+ if (abi_sp)
+ {
+ return abi_sp->CreateDefaultUnwindPlan (unwind_plan);
+ }
+ }
+ }
+ }
+ return false;
}
bool
diff --git a/source/Symbol/ClangASTContext.cpp b/source/Symbol/ClangASTContext.cpp
index aae96bfa9a3b..d851ae792181 100644
--- a/source/Symbol/ClangASTContext.cpp
+++ b/source/Symbol/ClangASTContext.cpp
@@ -11,6 +11,7 @@
// C Includes
// C++ Includes
+#include <mutex>
#include <string>
// Other libraries and framework includes
@@ -62,6 +63,7 @@
#include "lldb/Core/Flags.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/ThreadSafeDenseMap.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/Expression/ASTDumper.h"
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
@@ -79,13 +81,17 @@ using namespace lldb_private;
using namespace llvm;
using namespace clang;
-typedef llvm::DenseMap<clang::ASTContext *, ClangASTContext*> ClangASTMap;
+typedef lldb_private::ThreadSafeDenseMap<clang::ASTContext *, ClangASTContext*> ClangASTMap;
static ClangASTMap &
GetASTMap()
{
- static ClangASTMap g_map;
- return g_map;
+ static ClangASTMap *g_map_ptr = nullptr;
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+ g_map_ptr = new ClangASTMap(); // leaked on purpose to avoid spins
+ });
+ return *g_map_ptr;
}
@@ -303,7 +309,7 @@ ClangASTContext::~ClangASTContext()
{
if (m_ast_ap.get())
{
- GetASTMap().erase(m_ast_ap.get());
+ GetASTMap().Erase(m_ast_ap.get());
}
m_builtins_ap.reset();
@@ -409,7 +415,7 @@ ClangASTContext::getASTContext()
m_ast_ap->getDiagnostics().setClient(getDiagnosticConsumer(), false);
- GetASTMap().insert(std::make_pair(m_ast_ap.get(), this));
+ GetASTMap().Insert(m_ast_ap.get(), this);
}
return m_ast_ap.get();
}
@@ -417,7 +423,7 @@ ClangASTContext::getASTContext()
ClangASTContext*
ClangASTContext::GetASTContext (clang::ASTContext* ast)
{
- ClangASTContext *clang_ast = GetASTMap().lookup(ast);
+ ClangASTContext *clang_ast = GetASTMap().Lookup(ast);
return clang_ast;
}
@@ -883,6 +889,13 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name
break;
case DW_ATE_float:
+ if (streq(type_name, "float") && QualTypeMatchesBitSize (bit_size, ast, ast->FloatTy))
+ return ClangASTType (ast, ast->FloatTy.getAsOpaquePtr());
+ if (streq(type_name, "double") && QualTypeMatchesBitSize (bit_size, ast, ast->DoubleTy))
+ return ClangASTType (ast, ast->DoubleTy.getAsOpaquePtr());
+ if (streq(type_name, "long double") && QualTypeMatchesBitSize (bit_size, ast, ast->LongDoubleTy))
+ return ClangASTType (ast, ast->LongDoubleTy.getAsOpaquePtr());
+ // Fall back to not requring a name match
if (QualTypeMatchesBitSize (bit_size, ast, ast->FloatTy))
return ClangASTType (ast, ast->FloatTy.getAsOpaquePtr());
if (QualTypeMatchesBitSize (bit_size, ast, ast->DoubleTy))
@@ -1119,6 +1132,16 @@ ClangASTContext::AreTypesSame (ClangASTType type1,
return ast->hasSameType (type1_qual, type2_qual);
}
+ClangASTType
+ClangASTContext::GetTypeForDecl (clang::NamedDecl *decl)
+{
+ if (clang::ObjCInterfaceDecl *interface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl))
+ return GetTypeForDecl(interface_decl);
+ if (clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(decl))
+ return GetTypeForDecl(tag_decl);
+ return ClangASTType();
+}
+
ClangASTType
ClangASTContext::GetTypeForDecl (TagDecl *decl)
@@ -1126,7 +1149,7 @@ ClangASTContext::GetTypeForDecl (TagDecl *decl)
// No need to call the getASTContext() accessor (which can create the AST
// if it isn't created yet, because we can't have created a decl in this
// AST if our AST didn't already exist...
- ASTContext *ast = m_ast_ap.get();
+ ASTContext *ast = &decl->getASTContext();
if (ast)
return ClangASTType (ast, ast->getTagDeclType(decl).getAsOpaquePtr());
return ClangASTType();
@@ -1138,7 +1161,7 @@ ClangASTContext::GetTypeForDecl (ObjCInterfaceDecl *decl)
// No need to call the getASTContext() accessor (which can create the AST
// if it isn't created yet, because we can't have created a decl in this
// AST if our AST didn't already exist...
- ASTContext *ast = m_ast_ap.get();
+ ASTContext *ast = &decl->getASTContext();
if (ast)
return ClangASTType (ast, ast->getObjCInterfaceType(decl).getAsOpaquePtr());
return ClangASTType();
@@ -1733,7 +1756,7 @@ ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx,
DeclarationName (&ast->Idents.get(name)),
function_clang_type.GetQualType(),
nullptr,
- (FunctionDecl::StorageClass)storage,
+ (clang::StorageClass)storage,
is_inline,
hasWrittenPrototype,
isConstexprSpecified);
@@ -1747,7 +1770,7 @@ ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx,
DeclarationName (),
function_clang_type.GetQualType(),
nullptr,
- (FunctionDecl::StorageClass)storage,
+ (clang::StorageClass)storage,
is_inline,
hasWrittenPrototype,
isConstexprSpecified);
@@ -1799,7 +1822,7 @@ ClangASTContext::CreateParameterDeclaration (const char *name, const ClangASTTyp
name && name[0] ? &ast->Idents.get(name) : nullptr,
param_type.GetQualType(),
nullptr,
- (VarDecl::StorageClass)storage,
+ (clang::StorageClass)storage,
nullptr);
}
@@ -1849,7 +1872,23 @@ ClangASTContext::CreateArrayType (const ClangASTType &element_type,
return ClangASTType();
}
-
+ClangASTType
+ClangASTContext::GetOrCreateStructForIdentifier (const ConstString &type_name,
+ const std::initializer_list< std::pair < const char *, ClangASTType > >& type_fields,
+ bool packed)
+{
+ ClangASTType type;
+ if ((type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name)).IsValid())
+ return type;
+ type = CreateRecordType(nullptr, lldb::eAccessPublic, type_name.GetCString(), clang::TTK_Struct, lldb::eLanguageTypeC);
+ type.StartTagDeclarationDefinition();
+ for (const auto& field : type_fields)
+ type.AddFieldToRecordType(field.first, field.second, lldb::eAccessPublic, 0);
+ if (packed)
+ type.SetIsPacked();
+ type.CompleteTagDeclarationDefinition();
+ return type;
+}
#pragma mark Enumeration Types
@@ -2067,7 +2106,7 @@ ClangASTContext::SetMetadata (clang::ASTContext *ast,
ClangASTMetadata &metadata)
{
ClangExternalASTSourceCommon *external_source =
- static_cast<ClangExternalASTSourceCommon*>(ast->getExternalSource());
+ ClangExternalASTSourceCommon::Lookup(ast->getExternalSource());
if (external_source)
external_source->SetMetadata(object, metadata);
@@ -2078,7 +2117,7 @@ ClangASTContext::GetMetadata (clang::ASTContext *ast,
const void *object)
{
ClangExternalASTSourceCommon *external_source =
- static_cast<ClangExternalASTSourceCommon*>(ast->getExternalSource());
+ ClangExternalASTSourceCommon::Lookup(ast->getExternalSource());
if (external_source && external_source->HasMetadata(object))
return external_source->GetMetadata(object);
diff --git a/source/Symbol/ClangASTImporter.cpp b/source/Symbol/ClangASTImporter.cpp
index 6579afb2f748..a925f808f858 100644
--- a/source/Symbol/ClangASTImporter.cpp
+++ b/source/Symbol/ClangASTImporter.cpp
@@ -86,7 +86,7 @@ ClangASTImporter::CopyDecl (clang::ASTContext *dst_ast,
if (log)
{
- lldb::user_id_t user_id;
+ lldb::user_id_t user_id = LLDB_INVALID_UID;
ClangASTMetadata *metadata = GetDeclMetadata(decl);
if (metadata)
user_id = metadata->GetUserID();
diff --git a/source/Symbol/ClangASTType.cpp b/source/Symbol/ClangASTType.cpp
index a0878ae442c8..8b672fac4312 100644
--- a/source/Symbol/ClangASTType.cpp
+++ b/source/Symbol/ClangASTType.cpp
@@ -47,6 +47,7 @@
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
+#include <iterator>
#include <mutex>
using namespace lldb;
@@ -515,7 +516,7 @@ ClangASTType::GetNumberOfFunctionArguments () const
}
ClangASTType
-ClangASTType::GetFunctionArgumentAtIndex (const size_t index)
+ClangASTType::GetFunctionArgumentAtIndex (const size_t index) const
{
if (IsValid())
{
@@ -1713,7 +1714,7 @@ ClangASTType::GetFunctionArgumentCount () const
}
ClangASTType
-ClangASTType::GetFunctionArgumentTypeAtIndex (size_t idx)
+ClangASTType::GetFunctionArgumentTypeAtIndex (size_t idx) const
{
if (IsValid())
{
@@ -1741,6 +1742,199 @@ ClangASTType::GetFunctionReturnType () const
return ClangASTType();
}
+size_t
+ClangASTType::GetNumMemberFunctions () const
+{
+ size_t num_functions = 0;
+ if (IsValid())
+ {
+ clang::QualType qual_type(GetCanonicalQualType());
+ switch (qual_type->getTypeClass()) {
+ case clang::Type::Record:
+ if (GetCompleteQualType (m_ast, qual_type))
+ {
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+ if (cxx_record_decl)
+ num_functions = std::distance(cxx_record_decl->method_begin(), cxx_record_decl->method_end());
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ if (GetCompleteType())
+ {
+ const clang::ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
+ if (objc_class_type)
+ {
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
+ if (class_interface_decl)
+ num_functions = std::distance(class_interface_decl->meth_begin(), class_interface_decl->meth_end());
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType())
+ {
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
+ if (objc_class_type)
+ {
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ if (class_interface_decl)
+ num_functions = std::distance(class_interface_decl->meth_begin(), class_interface_decl->meth_end());
+ }
+ }
+ break;
+
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumMemberFunctions();
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetNumMemberFunctions();
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetNumMemberFunctions();
+
+ default:
+ break;
+ }
+ }
+ return num_functions;
+}
+
+TypeMemberFunctionImpl
+ClangASTType::GetMemberFunctionAtIndex (size_t idx)
+{
+ std::string name("");
+ MemberFunctionKind kind(MemberFunctionKind::eMemberFunctionKindUnknown);
+ ClangASTType type{};
+ clang::ObjCMethodDecl *method_decl(nullptr);
+ if (IsValid())
+ {
+ clang::QualType qual_type(GetCanonicalQualType());
+ switch (qual_type->getTypeClass()) {
+ case clang::Type::Record:
+ if (GetCompleteQualType (m_ast, qual_type))
+ {
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+ if (cxx_record_decl)
+ {
+ auto method_iter = cxx_record_decl->method_begin();
+ auto method_end = cxx_record_decl->method_end();
+ if (idx < static_cast<size_t>(std::distance(method_iter, method_end)))
+ {
+ std::advance(method_iter, idx);
+ auto method_decl = method_iter->getCanonicalDecl();
+ if (method_decl)
+ {
+ if (!method_decl->getName().empty())
+ name.assign(method_decl->getName().data());
+ else
+ name.clear();
+ if (method_decl->isStatic())
+ kind = lldb::eMemberFunctionKindStaticMethod;
+ else if (llvm::isa<clang::CXXConstructorDecl>(method_decl))
+ kind = lldb::eMemberFunctionKindConstructor;
+ else if (llvm::isa<clang::CXXDestructorDecl>(method_decl))
+ kind = lldb::eMemberFunctionKindDestructor;
+ else
+ kind = lldb::eMemberFunctionKindInstanceMethod;
+ type = ClangASTType(m_ast,method_decl->getType().getAsOpaquePtr());
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ if (GetCompleteType())
+ {
+ const clang::ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
+ if (objc_class_type)
+ {
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
+ if (class_interface_decl)
+ {
+ auto method_iter = class_interface_decl->meth_begin();
+ auto method_end = class_interface_decl->meth_end();
+ if (idx < static_cast<size_t>(std::distance(method_iter, method_end)))
+ {
+ std::advance(method_iter, idx);
+ method_decl = method_iter->getCanonicalDecl();
+ if (method_decl)
+ {
+ name = method_decl->getSelector().getAsString();
+ if (method_decl->isClassMethod())
+ kind = lldb::eMemberFunctionKindStaticMethod;
+ else
+ kind = lldb::eMemberFunctionKindInstanceMethod;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType())
+ {
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
+ if (objc_class_type)
+ {
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ if (class_interface_decl)
+ {
+ auto method_iter = class_interface_decl->meth_begin();
+ auto method_end = class_interface_decl->meth_end();
+ if (idx < static_cast<size_t>(std::distance(method_iter, method_end)))
+ {
+ std::advance(method_iter, idx);
+ method_decl = method_iter->getCanonicalDecl();
+ if (method_decl)
+ {
+ name = method_decl->getSelector().getAsString();
+ if (method_decl->isClassMethod())
+ kind = lldb::eMemberFunctionKindStaticMethod;
+ else
+ kind = lldb::eMemberFunctionKindInstanceMethod;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetMemberFunctionAtIndex(idx);
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetMemberFunctionAtIndex(idx);
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetMemberFunctionAtIndex(idx);
+
+ default:
+ break;
+ }
+ }
+
+ if (kind == eMemberFunctionKindUnknown)
+ return TypeMemberFunctionImpl();
+ if (method_decl)
+ return TypeMemberFunctionImpl(method_decl, name, kind);
+ if (type)
+ return TypeMemberFunctionImpl(type, name, kind);
+
+ return TypeMemberFunctionImpl();
+}
ClangASTType
ClangASTType::GetLValueReferenceType () const
@@ -3448,7 +3642,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
case clang::Type::IncompleteArray:
if (ignore_array_bounds || idx_is_valid)
{
- const clang::ArrayType *array = llvm::cast<clang::ArrayType>(parent_qual_type.getTypePtr());
+ const clang::ArrayType *array = GetQualType()->getAsArrayTypeUnsafe();
if (array)
{
ClangASTType element_type (m_ast, array->getElementType());
@@ -4752,6 +4946,17 @@ ClangASTType::BuildIndirectFields ()
}
}
+void
+ClangASTType::SetIsPacked ()
+{
+ clang::RecordDecl *record_decl = GetAsRecordDecl();
+
+ if (!record_decl)
+ return;
+
+ record_decl->addAttr(clang::PackedAttr::CreateImplicit(*m_ast));
+}
+
clang::VarDecl *
ClangASTType::AddVariableToRecordType (const char *name,
const ClangASTType &var_type,
@@ -5176,9 +5381,12 @@ ClangASTType::AddObjCClassProperty (const char *property_name,
if (getter && metadata)
ClangASTContext::SetMetadata(m_ast, getter, *metadata);
- getter->setMethodParams(*m_ast, llvm::ArrayRef<clang::ParmVarDecl*>(), llvm::ArrayRef<clang::SourceLocation>());
+ if (getter)
+ {
+ getter->setMethodParams(*m_ast, llvm::ArrayRef<clang::ParmVarDecl*>(), llvm::ArrayRef<clang::SourceLocation>());
- class_interface_decl->addDecl(getter);
+ class_interface_decl->addDecl(getter);
+ }
}
if (!setter_sel.isNull() && !class_interface_decl->lookupInstanceMethod(setter_sel))
@@ -5223,9 +5431,12 @@ ClangASTType::AddObjCClassProperty (const char *property_name,
clang::SC_Auto,
nullptr));
- setter->setMethodParams(*m_ast, llvm::ArrayRef<clang::ParmVarDecl*>(params), llvm::ArrayRef<clang::SourceLocation>());
+ if (setter)
+ {
+ setter->setMethodParams(*m_ast, llvm::ArrayRef<clang::ParmVarDecl*>(params), llvm::ArrayRef<clang::SourceLocation>());
- class_interface_decl->addDecl(setter);
+ class_interface_decl->addDecl(setter);
+ }
}
return true;
diff --git a/source/Symbol/ClangExternalASTSourceCommon.cpp b/source/Symbol/ClangExternalASTSourceCommon.cpp
index 650d252a8fc3..79cc9a91355a 100644
--- a/source/Symbol/ClangExternalASTSourceCommon.cpp
+++ b/source/Symbol/ClangExternalASTSourceCommon.cpp
@@ -9,30 +9,52 @@
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
#include "lldb/Core/Stream.h"
+#include "lldb/Host/Mutex.h"
using namespace lldb_private;
-#define ClangExternalASTSourceCommon_MAGIC (0x00112233aabbccddull)
-
uint64_t g_TotalSizeOfMetadata = 0;
-ClangExternalASTSourceCommon::ClangExternalASTSourceCommon() : clang::ExternalASTSource()
+typedef llvm::DenseMap<clang::ExternalASTSource *, ClangExternalASTSourceCommon *> ASTSourceMap;
+
+static ASTSourceMap &GetSourceMap()
+{
+ static ASTSourceMap s_source_map;
+ return s_source_map;
+}
+
+ClangExternalASTSourceCommon *
+ClangExternalASTSourceCommon::Lookup(clang::ExternalASTSource *source)
{
- m_magic = ClangExternalASTSourceCommon_MAGIC;
+ ASTSourceMap &source_map = GetSourceMap();
+
+ ASTSourceMap::iterator iter = source_map.find(source);
+ if (iter != source_map.end())
+ {
+ return iter->second;
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+ClangExternalASTSourceCommon::ClangExternalASTSourceCommon() : clang::ExternalASTSource()
+{
g_TotalSizeOfMetadata += m_metadata.size();
+ GetSourceMap()[this] = this;
}
ClangExternalASTSourceCommon::~ClangExternalASTSourceCommon()
{
+ GetSourceMap().erase(this);
g_TotalSizeOfMetadata -= m_metadata.size();
}
ClangASTMetadata *
ClangExternalASTSourceCommon::GetMetadata (const void *object)
{
- assert (m_magic == ClangExternalASTSourceCommon_MAGIC);
-
if (HasMetadata (object))
return &m_metadata[object];
else
@@ -42,8 +64,6 @@ ClangExternalASTSourceCommon::GetMetadata (const void *object)
void
ClangExternalASTSourceCommon::SetMetadata (const void *object, ClangASTMetadata &metadata)
{
- assert (m_magic == ClangExternalASTSourceCommon_MAGIC);
-
uint64_t orig_size = m_metadata.size();
m_metadata[object] = metadata;
uint64_t new_size = m_metadata.size();
@@ -53,8 +73,6 @@ ClangExternalASTSourceCommon::SetMetadata (const void *object, ClangASTMetadata
bool
ClangExternalASTSourceCommon::HasMetadata (const void *object)
{
- assert (m_magic == ClangExternalASTSourceCommon_MAGIC);
-
return m_metadata.find(object) != m_metadata.end();
}
diff --git a/source/Symbol/CompactUnwindInfo.cpp b/source/Symbol/CompactUnwindInfo.cpp
new file mode 100644
index 000000000000..8c6a2e7214c3
--- /dev/null
+++ b/source/Symbol/CompactUnwindInfo.cpp
@@ -0,0 +1,1215 @@
+//===-- CompactUnwindInfo.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+// C++ Includes
+#include <algorithm>
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompactUnwindInfo.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "llvm/Support/MathExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+namespace lldb_private {
+
+ // Constants from <mach-o/compact_unwind_encoding.h>
+
+ enum {
+ UNWIND_IS_NOT_FUNCTION_START = 0x80000000,
+ UNWIND_HAS_LSDA = 0x40000000,
+ UNWIND_PERSONALITY_MASK = 0x30000000,
+ };
+
+ enum {
+ UNWIND_X86_MODE_MASK = 0x0F000000,
+ UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
+ UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
+ UNWIND_X86_MODE_STACK_IND = 0x03000000,
+ UNWIND_X86_MODE_DWARF = 0x04000000,
+
+ UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
+ UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
+
+ UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
+ UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
+ UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
+ UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
+
+ UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+ };
+
+ enum {
+ UNWIND_X86_REG_NONE = 0,
+ UNWIND_X86_REG_EBX = 1,
+ UNWIND_X86_REG_ECX = 2,
+ UNWIND_X86_REG_EDX = 3,
+ UNWIND_X86_REG_EDI = 4,
+ UNWIND_X86_REG_ESI = 5,
+ UNWIND_X86_REG_EBP = 6,
+ };
+ enum {
+ UNWIND_X86_64_MODE_MASK = 0x0F000000,
+ UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
+ UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
+ UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
+ UNWIND_X86_64_MODE_DWARF = 0x04000000,
+
+ UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
+ UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
+
+ UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
+ UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
+ UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
+ UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
+
+ UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+ };
+
+ enum {
+ UNWIND_X86_64_REG_NONE = 0,
+ UNWIND_X86_64_REG_RBX = 1,
+ UNWIND_X86_64_REG_R12 = 2,
+ UNWIND_X86_64_REG_R13 = 3,
+ UNWIND_X86_64_REG_R14 = 4,
+ UNWIND_X86_64_REG_R15 = 5,
+ UNWIND_X86_64_REG_RBP = 6,
+ };
+};
+
+
+#ifndef UNWIND_SECOND_LEVEL_REGULAR
+#define UNWIND_SECOND_LEVEL_REGULAR 2
+#endif
+
+#ifndef UNWIND_SECOND_LEVEL_COMPRESSED
+#define UNWIND_SECOND_LEVEL_COMPRESSED 3
+#endif
+
+#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
+#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
+#endif
+
+#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
+#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF)
+#endif
+
+#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) )
+
+
+
+//----------------------
+// constructor
+//----------------------
+
+
+CompactUnwindInfo::CompactUnwindInfo(ObjectFile& objfile, SectionSP& section_sp) :
+ m_objfile (objfile),
+ m_section_sp (section_sp),
+ m_section_contents_if_encrypted (),
+ m_mutex (),
+ m_indexes (),
+ m_indexes_computed (eLazyBoolCalculate),
+ m_unwindinfo_data (),
+ m_unwindinfo_data_computed (false),
+ m_unwind_header ()
+{
+
+}
+
+//----------------------
+// destructor
+//----------------------
+
+CompactUnwindInfo::~CompactUnwindInfo()
+{
+}
+
+bool
+CompactUnwindInfo::GetUnwindPlan (Target &target, Address addr, UnwindPlan& unwind_plan)
+{
+ if (!IsValid (target.GetProcessSP()))
+ {
+ return false;
+ }
+ FunctionInfo function_info;
+ if (GetCompactUnwindInfoForFunction (target, addr, function_info))
+ {
+ // shortcut return for functions that have no compact unwind
+ if (function_info.encoding == 0)
+ return false;
+
+ ArchSpec arch;
+ if (m_objfile.GetArchitecture (arch))
+ {
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose())
+ {
+ StreamString strm;
+ addr.Dump (&strm, NULL, Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments, Address::DumpStyle::DumpStyleFileAddress, arch.GetAddressByteSize());
+ log->Printf ("Got compact unwind encoding 0x%x for function %s", function_info.encoding, strm.GetData());
+ }
+
+ if (function_info.valid_range_offset_start != 0 && function_info.valid_range_offset_end != 0)
+ {
+ SectionList *sl = m_objfile.GetSectionList ();
+ if (sl)
+ {
+ addr_t func_range_start_file_addr =
+ function_info.valid_range_offset_start + m_objfile.GetHeaderAddress().GetFileAddress();
+ AddressRange func_range (func_range_start_file_addr,
+ function_info.valid_range_offset_end - function_info.valid_range_offset_start,
+ sl);
+ unwind_plan.SetPlanValidAddressRange (func_range);
+ }
+ }
+
+ if (arch.GetTriple().getArch() == llvm::Triple::x86_64)
+ {
+ return CreateUnwindPlan_x86_64 (target, function_info, unwind_plan, addr);
+ }
+ if (arch.GetTriple().getArch() == llvm::Triple::x86)
+ {
+ return CreateUnwindPlan_i386 (target, function_info, unwind_plan, addr);
+ }
+ }
+ }
+ return false;
+}
+
+bool
+CompactUnwindInfo::IsValid (const ProcessSP &process_sp)
+{
+ if (m_section_sp.get() == nullptr)
+ return false;
+
+ if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
+ return true;
+
+ ScanIndex (process_sp);
+
+ return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
+}
+
+void
+CompactUnwindInfo::ScanIndex (const ProcessSP &process_sp)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
+ return;
+
+ // We can't read the index for some reason.
+ if (m_indexes_computed == eLazyBoolNo)
+ {
+ return;
+ }
+
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log)
+ m_objfile.GetModule()->LogMessage(log, "Reading compact unwind first-level indexes");
+
+ if (m_unwindinfo_data_computed == false)
+ {
+ if (m_section_sp->IsEncrypted())
+ {
+ // Can't get section contents of a protected/encrypted section until we have a live
+ // process and can read them out of memory.
+ if (process_sp.get() == nullptr)
+ return;
+ m_section_contents_if_encrypted.reset (new DataBufferHeap (m_section_sp->GetByteSize(), 0));
+ Error error;
+ if (process_sp->ReadMemory (
+ m_section_sp->GetLoadBaseAddress (&process_sp->GetTarget()),
+ m_section_contents_if_encrypted->GetBytes(),
+ m_section_sp->GetByteSize(), error) == m_section_sp->GetByteSize() && error.Success())
+ {
+ m_unwindinfo_data.SetAddressByteSize (process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
+ m_unwindinfo_data.SetByteOrder (process_sp->GetTarget().GetArchitecture().GetByteOrder());
+ m_unwindinfo_data.SetData (m_section_contents_if_encrypted, 0);
+ }
+ }
+ else
+ {
+ m_objfile.ReadSectionData (m_section_sp.get(), m_unwindinfo_data);
+ }
+ if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
+ return;
+ m_unwindinfo_data_computed = true;
+ }
+
+ if (m_unwindinfo_data.GetByteSize() > 0)
+ {
+ offset_t offset = 0;
+
+ // struct unwind_info_section_header
+ // {
+ // uint32_t version; // UNWIND_SECTION_VERSION
+ // uint32_t commonEncodingsArraySectionOffset;
+ // uint32_t commonEncodingsArrayCount;
+ // uint32_t personalityArraySectionOffset;
+ // uint32_t personalityArrayCount;
+ // uint32_t indexSectionOffset;
+ // uint32_t indexCount;
+
+ m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);
+ m_unwind_header.common_encodings_array_offset = m_unwindinfo_data.GetU32(&offset);
+ m_unwind_header.common_encodings_array_count = m_unwindinfo_data.GetU32(&offset);
+ m_unwind_header.personality_array_offset = m_unwindinfo_data.GetU32(&offset);
+ m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);
+ uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);
+
+ uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
+
+ if (m_unwind_header.version != 1)
+ {
+ m_indexes_computed = eLazyBoolNo;
+ }
+
+ // Parse the basic information from the indexes
+ // We wait to scan the second level page info until it's needed
+
+ // struct unwind_info_section_header_index_entry
+ // {
+ // uint32_t functionOffset;
+ // uint32_t secondLevelPagesSectionOffset;
+ // uint32_t lsdaIndexArraySectionOffset;
+ // };
+
+ offset = indexSectionOffset;
+ for (uint32_t idx = 0; idx < indexCount; idx++)
+ {
+ uint32_t function_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
+ uint32_t second_level_offset = m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset
+ uint32_t lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset
+
+ if (second_level_offset > m_section_sp->GetByteSize() || lsda_offset > m_section_sp->GetByteSize())
+ {
+ m_indexes_computed = eLazyBoolNo;
+ }
+
+ UnwindIndex this_index;
+ this_index.function_offset = function_offset; //
+ this_index.second_level = second_level_offset;
+ this_index.lsda_array_start = lsda_offset;
+
+ if (m_indexes.size() > 0)
+ {
+ m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
+ }
+
+ if (second_level_offset == 0)
+ {
+ this_index.sentinal_entry = true;
+ }
+
+ m_indexes.push_back (this_index);
+ }
+ m_indexes_computed = eLazyBoolYes;
+ }
+ else
+ {
+ m_indexes_computed = eLazyBoolNo;
+ }
+}
+
+uint32_t
+CompactUnwindInfo::GetLSDAForFunctionOffset (uint32_t lsda_offset, uint32_t lsda_count, uint32_t function_offset)
+{
+ // struct unwind_info_section_header_lsda_index_entry
+ // {
+ // uint32_t functionOffset;
+ // uint32_t lsdaOffset;
+ // };
+
+ offset_t first_entry = lsda_offset;
+ uint32_t low = 0;
+ uint32_t high = lsda_count;
+ while (low < high)
+ {
+ uint32_t mid = (low + high) / 2;
+ offset_t offset = first_entry + (mid * 8);
+ uint32_t mid_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
+ uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset
+ if (mid_func_offset == function_offset)
+ {
+ return mid_lsda_offset;
+ }
+ if (mid_func_offset < function_offset)
+ {
+ low = mid + 1;
+ }
+ else
+ {
+ high = mid;
+ }
+ }
+ return 0;
+}
+
+lldb::offset_t
+CompactUnwindInfo::BinarySearchRegularSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset)
+{
+ // typedef uint32_t compact_unwind_encoding_t;
+ // struct unwind_info_regular_second_level_entry
+ // {
+ // uint32_t functionOffset;
+ // compact_unwind_encoding_t encoding;
+
+ offset_t first_entry = entry_page_offset;
+
+ uint32_t low = 0;
+ uint32_t high = entry_count;
+ uint32_t last = high - 1;
+ while (low < high)
+ {
+ uint32_t mid = (low + high) / 2;
+ offset_t offset = first_entry + (mid * 8);
+ uint32_t mid_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
+ uint32_t next_func_offset = 0;
+ if (mid < last)
+ {
+ offset = first_entry + ((mid + 1) * 8);
+ next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
+ }
+ if (mid_func_offset <= function_offset)
+ {
+ if (mid == last || (next_func_offset > function_offset))
+ {
+ if (entry_func_start_offset)
+ *entry_func_start_offset = mid_func_offset;
+ if (mid != last && entry_func_end_offset)
+ *entry_func_end_offset = next_func_offset;
+ return first_entry + (mid * 8);
+ }
+ else
+ {
+ low = mid + 1;
+ }
+ }
+ else
+ {
+ high = mid;
+ }
+ }
+ return LLDB_INVALID_OFFSET;
+}
+
+uint32_t
+CompactUnwindInfo::BinarySearchCompressedSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset_to_find, uint32_t function_offset_base, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset)
+{
+ offset_t first_entry = entry_page_offset;
+
+ uint32_t low = 0;
+ uint32_t high = entry_count;
+ uint32_t last = high - 1;
+ while (low < high)
+ {
+ uint32_t mid = (low + high) / 2;
+ offset_t offset = first_entry + (mid * 4);
+ uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry
+ uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (entry);
+ mid_func_offset += function_offset_base;
+ uint32_t next_func_offset = 0;
+ if (mid < last)
+ {
+ offset = first_entry + ((mid + 1) * 4);
+ uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry
+ next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (next_entry);
+ next_func_offset += function_offset_base;
+ }
+ if (mid_func_offset <= function_offset_to_find)
+ {
+ if (mid == last || (next_func_offset > function_offset_to_find))
+ {
+ if (entry_func_start_offset)
+ *entry_func_start_offset = mid_func_offset;
+ if (mid != last && entry_func_end_offset)
+ *entry_func_end_offset = next_func_offset;
+ return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX (entry);
+ }
+ else
+ {
+ low = mid + 1;
+ }
+ }
+ else
+ {
+ high = mid;
+ }
+ }
+
+ return UINT32_MAX;
+}
+
+bool
+CompactUnwindInfo::GetCompactUnwindInfoForFunction (Target &target, Address address, FunctionInfo &unwind_info)
+{
+ unwind_info.encoding = 0;
+ unwind_info.lsda_address.Clear();
+ unwind_info.personality_ptr_address.Clear();
+
+ if (!IsValid (target.GetProcessSP()))
+ return false;
+
+ addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
+ SectionList *sl = m_objfile.GetSectionList ();
+ if (sl)
+ {
+ SectionSP text_sect = sl->FindSectionByType (eSectionTypeCode, true);
+ if (text_sect.get())
+ {
+ text_section_file_address = text_sect->GetFileAddress();
+ }
+ }
+ if (text_section_file_address == LLDB_INVALID_ADDRESS)
+ return false;
+
+ addr_t function_offset = address.GetFileAddress() - m_objfile.GetHeaderAddress().GetFileAddress();
+
+ UnwindIndex key;
+ key.function_offset = function_offset;
+
+ std::vector<UnwindIndex>::const_iterator it;
+ it = std::lower_bound (m_indexes.begin(), m_indexes.end(), key);
+ if (it == m_indexes.end())
+ {
+ return false;
+ }
+
+ if (it->function_offset != key.function_offset)
+ {
+ if (it != m_indexes.begin())
+ --it;
+ }
+
+ if (it->sentinal_entry == true)
+ {
+ return false;
+ }
+
+ auto next_it = it + 1;
+ if (next_it != m_indexes.begin())
+ {
+ // 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
+ // the index table, this will establish the range end.
+ unwind_info.valid_range_offset_end = next_it->function_offset;
+ }
+
+ offset_t second_page_offset = it->second_level;
+ offset_t lsda_array_start = it->lsda_array_start;
+ offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
+
+ offset_t offset = second_page_offset;
+ uint32_t kind = m_unwindinfo_data.GetU32(&offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED
+
+ if (kind == UNWIND_SECOND_LEVEL_REGULAR)
+ {
+ // struct unwind_info_regular_second_level_page_header
+ // {
+ // uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
+ // uint16_t entryPageOffset;
+ // uint16_t entryCount;
+
+ // typedef uint32_t compact_unwind_encoding_t;
+ // struct unwind_info_regular_second_level_entry
+ // {
+ // uint32_t functionOffset;
+ // compact_unwind_encoding_t encoding;
+
+ uint16_t entry_page_offset = m_unwindinfo_data.GetU16(&offset); // entryPageOffset
+ uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
+
+ offset_t entry_offset = BinarySearchRegularSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset, &unwind_info.valid_range_offset_start, &unwind_info.valid_range_offset_end);
+ if (entry_offset == LLDB_INVALID_OFFSET)
+ {
+ return false;
+ }
+ entry_offset += 4; // skip over functionOffset
+ unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding
+ if (unwind_info.encoding & UNWIND_HAS_LSDA)
+ {
+ SectionList *sl = m_objfile.GetSectionList ();
+ if (sl)
+ {
+ uint32_t lsda_offset = GetLSDAForFunctionOffset (lsda_array_start, lsda_array_count, function_offset);
+ addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
+ unwind_info.lsda_address.ResolveAddressUsingFileSections (objfile_header_file_address + lsda_offset, sl);
+ }
+ }
+ if (unwind_info.encoding & UNWIND_PERSONALITY_MASK)
+ {
+ uint32_t personality_index = EXTRACT_BITS (unwind_info.encoding, UNWIND_PERSONALITY_MASK);
+
+ if (personality_index > 0)
+ {
+ personality_index--;
+ if (personality_index < m_unwind_header.personality_array_count)
+ {
+ offset_t offset = m_unwind_header.personality_array_offset;
+ offset += 4 * personality_index;
+ SectionList *sl = m_objfile.GetSectionList ();
+ if (sl)
+ {
+ uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
+ addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
+ unwind_info.personality_ptr_address.ResolveAddressUsingFileSections (objfile_header_file_address + personality_offset, sl);
+ }
+ }
+ }
+ }
+ return true;
+ }
+ else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED)
+ {
+ // struct unwind_info_compressed_second_level_page_header
+ // {
+ // uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED
+ // uint16_t entryPageOffset; // offset from this 2nd lvl page idx to array of entries
+ // // (an entry has a function offset and index into the encodings)
+ // // NB function offset from the entry in the compressed page
+ // // must be added to the index's functionOffset value.
+ // uint16_t entryCount;
+ // uint16_t encodingsPageOffset; // offset from this 2nd lvl page idx to array of encodings
+ // uint16_t encodingsCount;
+
+ uint16_t entry_page_offset = m_unwindinfo_data.GetU16(&offset); // entryPageOffset
+ uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
+ uint16_t encodings_page_offset = m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
+ uint16_t encodings_count = m_unwindinfo_data.GetU16(&offset); // encodingsCount
+
+ uint32_t encoding_index = BinarySearchCompressedSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset, it->function_offset, &unwind_info.valid_range_offset_start, &unwind_info.valid_range_offset_end);
+ if (encoding_index == UINT32_MAX || encoding_index >= encodings_count + m_unwind_header.common_encodings_array_count)
+ {
+ return false;
+ }
+ uint32_t encoding = 0;
+ if (encoding_index < m_unwind_header.common_encodings_array_count)
+ {
+ offset = m_unwind_header.common_encodings_array_offset + (encoding_index * sizeof (uint32_t));
+ encoding = m_unwindinfo_data.GetU32(&offset); // encoding entry from the commonEncodingsArray
+ }
+ else
+ {
+ uint32_t page_specific_entry_index = encoding_index - m_unwind_header.common_encodings_array_count;
+ offset = second_page_offset + encodings_page_offset + (page_specific_entry_index * sizeof (uint32_t));
+ encoding = m_unwindinfo_data.GetU32(&offset); // encoding entry from the page-specific encoding array
+ }
+ if (encoding == 0)
+ return false;
+
+ unwind_info.encoding = encoding;
+ if (unwind_info.encoding & UNWIND_HAS_LSDA)
+ {
+ SectionList *sl = m_objfile.GetSectionList ();
+ if (sl)
+ {
+ uint32_t lsda_offset = GetLSDAForFunctionOffset (lsda_array_start, lsda_array_count, function_offset);
+ addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
+ unwind_info.lsda_address.ResolveAddressUsingFileSections (objfile_header_file_address + lsda_offset, sl);
+ }
+ }
+ if (unwind_info.encoding & UNWIND_PERSONALITY_MASK)
+ {
+ uint32_t personality_index = EXTRACT_BITS (unwind_info.encoding, UNWIND_PERSONALITY_MASK);
+
+ if (personality_index > 0)
+ {
+ personality_index--;
+ if (personality_index < m_unwind_header.personality_array_count)
+ {
+ offset_t offset = m_unwind_header.personality_array_offset;
+ offset += 4 * personality_index;
+ SectionList *sl = m_objfile.GetSectionList ();
+ if (sl)
+ {
+ uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
+ addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
+ unwind_info.personality_ptr_address.ResolveAddressUsingFileSections (objfile_header_file_address + personality_offset, sl);
+ }
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+enum x86_64_eh_regnum {
+ rax = 0,
+ rdx = 1,
+ rcx = 2,
+ rbx = 3,
+ rsi = 4,
+ rdi = 5,
+ rbp = 6,
+ rsp = 7,
+ r8 = 8,
+ r9 = 9,
+ r10 = 10,
+ r11 = 11,
+ r12 = 12,
+ r13 = 13,
+ r14 = 14,
+ r15 = 15,
+ rip = 16 // this is officially the Return Address register number, but close enough
+};
+
+// Convert the compact_unwind_info.h register numbering scheme
+// to eRegisterKindGCC (eh_frame) register numbering scheme.
+uint32_t
+translate_to_eh_frame_regnum_x86_64 (uint32_t unwind_regno)
+{
+ switch (unwind_regno)
+ {
+ case UNWIND_X86_64_REG_RBX:
+ return x86_64_eh_regnum::rbx;
+ case UNWIND_X86_64_REG_R12:
+ return x86_64_eh_regnum::r12;
+ case UNWIND_X86_64_REG_R13:
+ return x86_64_eh_regnum::r13;
+ case UNWIND_X86_64_REG_R14:
+ return x86_64_eh_regnum::r14;
+ case UNWIND_X86_64_REG_R15:
+ return x86_64_eh_regnum::r15;
+ case UNWIND_X86_64_REG_RBP:
+ return x86_64_eh_regnum::rbp;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+}
+
+bool
+CompactUnwindInfo::CreateUnwindPlan_x86_64 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start)
+{
+ unwind_plan.SetSourceName ("compact unwind info");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ unwind_plan.SetRegisterKind (eRegisterKindGCC);
+
+ unwind_plan.SetLSDAAddress (function_info.lsda_address);
+ unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address);
+
+ UnwindPlan::RowSP row (new UnwindPlan::Row);
+
+ const int wordsize = 8;
+ int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
+ switch (mode)
+ {
+ 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->SetOffset (0);
+ row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rbp, wordsize * -2, true);
+ row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true);
+ row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true);
+
+ uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
+
+ uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
+
+ saved_registers_offset += 2;
+
+ for (int i = 0; i < 5; i++)
+ {
+ uint32_t regnum = saved_registers_locations & 0x7;
+ switch (regnum)
+ {
+ case UNWIND_X86_64_REG_NONE:
+ break;
+ case UNWIND_X86_64_REG_RBX:
+ case UNWIND_X86_64_REG_R12:
+ case UNWIND_X86_64_REG_R13:
+ case UNWIND_X86_64_REG_R14:
+ case UNWIND_X86_64_REG_R15:
+ row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (regnum), wordsize * -saved_registers_offset, true);
+ break;
+ }
+ saved_registers_offset--;
+ saved_registers_locations >>= 3;
+ }
+ unwind_plan.AppendRow (row);
+ return true;
+ }
+ break;
+
+ 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.
+ return false;
+ }
+ break;
+
+ case UNWIND_X86_64_MODE_STACK_IMMD:
+ {
+ uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+ uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
+
+ if (mode == UNWIND_X86_64_MODE_STACK_IND && function_info.valid_range_offset_start != 0)
+ {
+ uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
+
+ // offset into the function instructions; 0 == beginning of first instruction
+ uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+
+ SectionList *sl = m_objfile.GetSectionList ();
+ if (sl)
+ {
+ ProcessSP process_sp = target.GetProcessSP();
+ if (process_sp)
+ {
+ Address subl_payload_addr (function_info.valid_range_offset_start, sl);
+ subl_payload_addr.Slide (offset_to_subl_insn);
+ Error error;
+ uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target),
+ 4, 0, error);
+ if (large_stack_size != 0 && error.Success ())
+ {
+ // Got the large stack frame size correctly - use it
+ stack_size = large_stack_size + (stack_adjust * wordsize);
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ row->SetCFARegister (x86_64_eh_regnum::rsp);
+ row->SetCFAOffset (stack_size * wordsize);
+ row->SetOffset (0);
+ row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true);
+ row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true);
+
+ if (register_count > 0)
+ {
+
+ // We need to include (up to) 6 registers in 10 bits.
+ // That would be 18 bits if we just used 3 bits per reg to indicate
+ // the order they're saved on the stack.
+ //
+ // This is done with Lehmer code permutation, e.g. see
+ // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
+ int permunreg[6];
+
+ // This decodes the variable-base number in the 10 bits
+ // and gives us the Lehmer code sequence which can then
+ // be decoded.
+
+ switch (register_count)
+ {
+ case 6:
+ permunreg[0] = permutation/120; // 120 == 5!
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24; // 24 == 4!
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6; // 6 == 3!
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2; // 2 == 2!
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation; // 1 == 1!
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation/60;
+ permutation -= (permunreg[0]*60);
+ permunreg[1] = permutation/12;
+ permutation -= (permunreg[1]*12);
+ permunreg[2] = permutation/3;
+ permutation -= (permunreg[2]*3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation/20;
+ permutation -= (permunreg[0]*20);
+ permunreg[1] = permutation/4;
+ permutation -= (permunreg[1]*4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation/5;
+ permutation -= (permunreg[0]*5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+
+ // Decode the Lehmer code for this permutation of
+ // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
+
+ int registers[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (uint32_t i = 0; i < register_count; i++)
+ {
+ int renum = 0;
+ for (int j = 1; j < 7; j++)
+ {
+ if (used[j] == false)
+ {
+ if (renum == permunreg[i])
+ {
+ registers[i] = j;
+ used[j] = true;
+ break;
+ }
+ renum++;
+ }
+ }
+ }
+
+ uint32_t saved_registers_offset = 1;
+ saved_registers_offset++;
+
+ for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
+ {
+ switch (registers[i])
+ {
+ case UNWIND_X86_64_REG_NONE:
+ break;
+ case UNWIND_X86_64_REG_RBX:
+ case UNWIND_X86_64_REG_R12:
+ case UNWIND_X86_64_REG_R13:
+ case UNWIND_X86_64_REG_R14:
+ case UNWIND_X86_64_REG_R15:
+ case UNWIND_X86_64_REG_RBP:
+ row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (registers[i]), wordsize * -saved_registers_offset, true);
+ break;
+ }
+ saved_registers_offset++;
+ }
+ }
+ unwind_plan.AppendRow (row);
+ return true;
+ }
+ break;
+
+ case UNWIND_X86_64_MODE_DWARF:
+ {
+ return false;
+ }
+ break;
+
+ case 0:
+ {
+ return false;
+ }
+ break;
+ }
+ return false;
+}
+
+enum i386_eh_regnum {
+ eax = 0,
+ ecx = 1,
+ edx = 2,
+ ebx = 3,
+ ebp = 4,
+ esp = 5,
+ esi = 6,
+ edi = 7,
+ eip = 8 // this is officially the Return Address register number, but close enough
+};
+
+// Convert the compact_unwind_info.h register numbering scheme
+// to eRegisterKindGCC (eh_frame) register numbering scheme.
+uint32_t
+translate_to_eh_frame_regnum_i386 (uint32_t unwind_regno)
+{
+ switch (unwind_regno)
+ {
+ case UNWIND_X86_REG_EBX:
+ return i386_eh_regnum::ebx;
+ case UNWIND_X86_REG_ECX:
+ return i386_eh_regnum::ecx;
+ case UNWIND_X86_REG_EDX:
+ return i386_eh_regnum::edx;
+ case UNWIND_X86_REG_EDI:
+ return i386_eh_regnum::edi;
+ case UNWIND_X86_REG_ESI:
+ return i386_eh_regnum::esi;
+ case UNWIND_X86_REG_EBP:
+ return i386_eh_regnum::ebp;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+}
+
+
+bool
+CompactUnwindInfo::CreateUnwindPlan_i386 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start)
+{
+ unwind_plan.SetSourceName ("compact unwind info");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ unwind_plan.SetRegisterKind (eRegisterKindGCC);
+
+ unwind_plan.SetLSDAAddress (function_info.lsda_address);
+ unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address);
+
+ UnwindPlan::RowSP row (new UnwindPlan::Row);
+
+ const int wordsize = 4;
+ int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
+ switch (mode)
+ {
+ case UNWIND_X86_MODE_EBP_FRAME:
+ {
+ row->SetCFARegister (translate_to_eh_frame_regnum_i386 (UNWIND_X86_REG_EBP));
+ row->SetCFAOffset (2 * wordsize);
+ row->SetOffset (0);
+ row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::ebp, wordsize * -2, true);
+ row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true);
+ row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true);
+
+ uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
+
+ uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
+
+ saved_registers_offset += 2;
+
+ for (int i = 0; i < 5; i++)
+ {
+ uint32_t regnum = saved_registers_locations & 0x7;
+ switch (regnum)
+ {
+ case UNWIND_X86_REG_NONE:
+ break;
+ case UNWIND_X86_REG_EBX:
+ case UNWIND_X86_REG_ECX:
+ case UNWIND_X86_REG_EDX:
+ case UNWIND_X86_REG_EDI:
+ case UNWIND_X86_REG_ESI:
+ row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (regnum), wordsize * -saved_registers_offset, true);
+ break;
+ }
+ saved_registers_offset--;
+ saved_registers_locations >>= 3;
+ }
+ unwind_plan.AppendRow (row);
+ return true;
+ }
+ break;
+
+ case UNWIND_X86_MODE_STACK_IND:
+ case UNWIND_X86_MODE_STACK_IMMD:
+ {
+ uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
+ uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
+
+ if (mode == UNWIND_X86_MODE_STACK_IND && function_info.valid_range_offset_start != 0)
+ {
+ uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
+
+ // offset into the function instructions; 0 == beginning of first instruction
+ uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
+
+ SectionList *sl = m_objfile.GetSectionList ();
+ if (sl)
+ {
+ ProcessSP process_sp = target.GetProcessSP();
+ if (process_sp)
+ {
+ Address subl_payload_addr (function_info.valid_range_offset_start, sl);
+ subl_payload_addr.Slide (offset_to_subl_insn);
+ Error error;
+ uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target),
+ 4, 0, error);
+ if (large_stack_size != 0 && error.Success ())
+ {
+ // Got the large stack frame size correctly - use it
+ stack_size = large_stack_size + (stack_adjust * wordsize);
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ row->SetCFARegister (i386_eh_regnum::esp);
+ row->SetCFAOffset (stack_size * wordsize);
+ row->SetOffset (0);
+ row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true);
+ row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true);
+
+ if (register_count > 0)
+ {
+
+ // We need to include (up to) 6 registers in 10 bits.
+ // That would be 18 bits if we just used 3 bits per reg to indicate
+ // the order they're saved on the stack.
+ //
+ // This is done with Lehmer code permutation, e.g. see
+ // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
+ int permunreg[6];
+
+ // This decodes the variable-base number in the 10 bits
+ // and gives us the Lehmer code sequence which can then
+ // be decoded.
+
+ switch (register_count)
+ {
+ case 6:
+ permunreg[0] = permutation/120; // 120 == 5!
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24; // 24 == 4!
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6; // 6 == 3!
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2; // 2 == 2!
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation; // 1 == 1!
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation/60;
+ permutation -= (permunreg[0]*60);
+ permunreg[1] = permutation/12;
+ permutation -= (permunreg[1]*12);
+ permunreg[2] = permutation/3;
+ permutation -= (permunreg[2]*3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation/20;
+ permutation -= (permunreg[0]*20);
+ permunreg[1] = permutation/4;
+ permutation -= (permunreg[1]*4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation/5;
+ permutation -= (permunreg[0]*5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+
+ // Decode the Lehmer code for this permutation of
+ // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
+
+ int registers[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (uint32_t i = 0; i < register_count; i++)
+ {
+ int renum = 0;
+ for (int j = 1; j < 7; j++)
+ {
+ if (used[j] == false)
+ {
+ if (renum == permunreg[i])
+ {
+ registers[i] = j;
+ used[j] = true;
+ break;
+ }
+ renum++;
+ }
+ }
+ }
+
+ uint32_t saved_registers_offset = 1;
+ saved_registers_offset++;
+
+ for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
+ {
+ switch (registers[i])
+ {
+ case UNWIND_X86_REG_NONE:
+ break;
+ case UNWIND_X86_REG_EBX:
+ case UNWIND_X86_REG_ECX:
+ case UNWIND_X86_REG_EDX:
+ case UNWIND_X86_REG_EDI:
+ case UNWIND_X86_REG_ESI:
+ case UNWIND_X86_REG_EBP:
+ row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (registers[i]), wordsize * -saved_registers_offset, true);
+ break;
+ }
+ saved_registers_offset++;
+ }
+ }
+
+ unwind_plan.AppendRow (row);
+ return true;
+ }
+ break;
+
+ case UNWIND_X86_MODE_DWARF:
+ {
+ return false;
+ }
+ break;
+ }
+ return false;
+}
diff --git a/source/Symbol/CompileUnit.cpp b/source/Symbol/CompileUnit.cpp
index f99ca53d9629..6483258ee678 100644
--- a/source/Symbol/CompileUnit.cpp
+++ b/source/Symbol/CompileUnit.cpp
@@ -325,18 +325,19 @@ CompileUnit::ResolveSymbolContext
// when finding file indexes
std::vector<uint32_t> file_indexes;
const bool full_match = (bool)file_spec.GetDirectory();
- bool file_spec_matches_cu_file_spec = FileSpec::Equal(file_spec, *this, full_match);
+ const bool remove_backup_dots = true;
+ bool file_spec_matches_cu_file_spec = FileSpec::Equal(file_spec, *this, full_match, remove_backup_dots);
// If we are not looking for inlined functions and our file spec doesn't
// match then we are done...
if (file_spec_matches_cu_file_spec == false && check_inlines == false)
return 0;
- uint32_t file_idx = GetSupportFiles().FindFileIndex (1, file_spec, true);
+ uint32_t file_idx = GetSupportFiles().FindFileIndex (1, file_spec, true, remove_backup_dots);
while (file_idx != UINT32_MAX)
{
file_indexes.push_back (file_idx);
- file_idx = GetSupportFiles().FindFileIndex (file_idx + 1, file_spec, true);
+ file_idx = GetSupportFiles().FindFileIndex (file_idx + 1, file_spec, true, remove_backup_dots);
}
const size_t num_file_indexes = file_indexes.size();
diff --git a/source/Symbol/DWARFCallFrameInfo.cpp b/source/Symbol/DWARFCallFrameInfo.cpp
index a9da631eb452..78d262307c24 100644
--- a/source/Symbol/DWARFCallFrameInfo.cpp
+++ b/source/Symbol/DWARFCallFrameInfo.cpp
@@ -218,20 +218,27 @@ DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset)
// FDE, which is the address of a language-specific
// data area (LSDA). The size of the LSDA pointer is
// specified by the pointer encoding used.
- m_cfi_data.GetU8(&offset);
+ cie_sp->lsda_addr_encoding = m_cfi_data.GetU8(&offset);
break;
case 'P':
// Indicates the presence of two arguments in the
- // Augmentation Data of the cie_sp-> The first argument
+ // Augmentation Data of the CIE. The first argument
// is 1-byte and represents the pointer encoding
// used for the second argument, which is the
// address of a personality routine handler. The
// size of the personality routine pointer is
// specified by the pointer encoding used.
+ //
+ // The address of the personality function will
+ // be stored at this location. Pre-execution, it
+ // will be all zero's so don't read it until we're
+ // trying to do an unwind & the reloc has been
+ // resolved.
{
uint8_t arg_ptr_encoding = m_cfi_data.GetU8(&offset);
- m_cfi_data.GetGNUEHPointer(&offset, arg_ptr_encoding, LLDB_INVALID_ADDRESS, LLDB_INVALID_ADDRESS, LLDB_INVALID_ADDRESS);
+ const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();
+ cie_sp->personality_loc = m_cfi_data.GetGNUEHPointer(&offset, arg_ptr_encoding, pc_rel_addr, LLDB_INVALID_ADDRESS, LLDB_INVALID_ADDRESS);
}
break;
@@ -449,11 +456,39 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
AddressRange range (range_base, m_objfile.GetAddressByteSize(), m_objfile.GetSectionList());
range.SetByteSize (range_len);
+ addr_t lsda_data_file_address = LLDB_INVALID_ADDRESS;
+
if (cie->augmentation[0] == 'z')
{
uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit)
+ {
+ offset_t saved_offset = offset;
+ lsda_data_file_address = m_cfi_data.GetGNUEHPointer(&offset, cie->lsda_addr_encoding, pc_rel_addr, text_addr, data_addr);
+ if (offset - saved_offset != aug_data_len)
+ {
+ // There is more in the augmentation region than we know how to process;
+ // don't read anything.
+ lsda_data_file_address = LLDB_INVALID_ADDRESS;
+ }
+ offset = saved_offset;
+ }
offset += aug_data_len;
}
+ Address lsda_data;
+ Address personality_function_ptr;
+
+ if (lsda_data_file_address != LLDB_INVALID_ADDRESS && cie->personality_loc != LLDB_INVALID_ADDRESS)
+ {
+ m_objfile.GetModule()->ResolveFileAddress (lsda_data_file_address, lsda_data);
+ m_objfile.GetModule()->ResolveFileAddress (cie->personality_loc, personality_function_ptr);
+ }
+
+ if (lsda_data.IsValid() && personality_function_ptr.IsValid())
+ {
+ unwind_plan.SetLSDAAddress (lsda_data);
+ unwind_plan.SetPersonalityFunctionPtr (personality_function_ptr);
+ }
uint32_t reg_num = 0;
int32_t op_offset = 0;
diff --git a/source/Symbol/Declaration.cpp b/source/Symbol/Declaration.cpp
index 3943f02c5474..c72ca045b6c7 100644
--- a/source/Symbol/Declaration.cpp
+++ b/source/Symbol/Declaration.cpp
@@ -110,7 +110,7 @@ lldb_private::operator == (const Declaration &lhs, const Declaration &rhs)
return lhs.GetFile() == rhs.GetFile();
#else
if (lhs.GetLine () == rhs.GetLine ())
- return lhs.GetFile() == rhs.GetFile();
+ return FileSpec::Equal(lhs.GetFile(),rhs.GetFile(), true, true);
#endif
return false;
}
diff --git a/source/Symbol/FuncUnwinders.cpp b/source/Symbol/FuncUnwinders.cpp
index 95fc81747859..1eb73ee3649b 100644
--- a/source/Symbol/FuncUnwinders.cpp
+++ b/source/Symbol/FuncUnwinders.cpp
@@ -11,6 +11,7 @@
#include "lldb/Core/Address.h"
#include "lldb/Symbol/FuncUnwinders.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/CompactUnwindInfo.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Symbol/UnwindTable.h"
@@ -24,145 +25,212 @@
using namespace lldb;
using namespace lldb_private;
+//------------------------------------------------
+/// constructor
+//------------------------------------------------
-FuncUnwinders::FuncUnwinders
-(
- UnwindTable& unwind_table,
- AddressRange range
-) :
- m_unwind_table(unwind_table),
- m_range(range),
+FuncUnwinders::FuncUnwinders (UnwindTable& unwind_table, AddressRange range) :
+ m_unwind_table (unwind_table),
+ m_range (range),
m_mutex (Mutex::eMutexTypeRecursive),
- m_unwind_plan_call_site_sp (),
- m_unwind_plan_non_call_site_sp (),
+ m_unwind_plan_assembly_sp (),
+ m_unwind_plan_eh_frame_sp (),
+ m_unwind_plan_eh_frame_augmented_sp (),
+ m_unwind_plan_compact_unwind (),
m_unwind_plan_fast_sp (),
m_unwind_plan_arch_default_sp (),
- m_tried_unwind_at_call_site (false),
- m_tried_unwind_at_non_call_site (false),
+ m_unwind_plan_arch_default_at_func_entry_sp (),
+ m_tried_unwind_plan_assembly (false),
+ m_tried_unwind_plan_eh_frame (false),
+ m_tried_unwind_plan_eh_frame_augmented (false),
+ m_tried_unwind_plan_compact_unwind (false),
m_tried_unwind_fast (false),
m_tried_unwind_arch_default (false),
m_tried_unwind_arch_default_at_func_entry (false),
- m_first_non_prologue_insn()
+ m_first_non_prologue_insn ()
{
}
-FuncUnwinders::~FuncUnwinders ()
+//------------------------------------------------
+/// destructor
+//------------------------------------------------
+
+FuncUnwinders::~FuncUnwinders ()
{
}
UnwindPlanSP
-FuncUnwinders::GetUnwindPlanAtCallSite (int current_offset)
+FuncUnwinders::GetUnwindPlanAtCallSite (Target &target, int current_offset)
{
- // Lock the mutex to ensure we can always give out the most appropriate
- // information. We want to make sure if someone requests a call site unwind
- // plan, that they get one and don't run into a race condition where one
- // thread has started to create the unwind plan and has put it into
- // m_unwind_plan_call_site_sp, and have another thread enter this function
- // and return the partially filled in m_unwind_plan_call_site_sp pointer.
- // We also want to make sure that we lock out other unwind plans from
- // being accessed until this one is done creating itself in case someone
- // had some code like:
- // UnwindPlan *best_unwind_plan = ...GetUnwindPlanAtCallSite (...)
- // if (best_unwind_plan == NULL)
- // best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
Mutex::Locker locker (m_mutex);
- if (m_tried_unwind_at_call_site == false && m_unwind_plan_call_site_sp.get() == nullptr)
+
+ UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, current_offset);
+ if (unwind_plan_sp.get() == nullptr)
{
- m_tried_unwind_at_call_site = true;
- // We have cases (e.g. with _sigtramp on Mac OS X) where the hand-written eh_frame unwind info for a
- // function does not cover the entire range of the function and so the FDE only lists a subset of the
- // address range. If we try to look up the unwind info by the starting address of the function
- // (i.e. m_range.GetBaseAddress()) we may not find the eh_frame FDE. We need to use the actual byte offset
- // into the function when looking it up.
-
- if (m_range.GetBaseAddress().IsValid())
- {
- Address current_pc (m_range.GetBaseAddress ());
- if (current_offset != -1)
- current_pc.SetOffset (current_pc.GetOffset() + current_offset);
+ unwind_plan_sp = GetCompactUnwindUnwindPlan (target, current_offset);
+ }
+
+ return unwind_plan_sp;
+}
- DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
- if (eh_frame)
+UnwindPlanSP
+FuncUnwinders::GetCompactUnwindUnwindPlan (Target &target, int current_offset)
+{
+ if (m_unwind_plan_compact_unwind.size() > 0)
+ return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact unwind plans for one func
+ if (m_tried_unwind_plan_compact_unwind)
+ return UnwindPlanSP();
+
+ Mutex::Locker lock (m_mutex);
+ m_tried_unwind_plan_compact_unwind = true;
+ if (m_range.GetBaseAddress().IsValid())
+ {
+ Address current_pc (m_range.GetBaseAddress ());
+ if (current_offset != -1)
+ current_pc.SetOffset (current_pc.GetOffset() + current_offset);
+ CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo();
+ if (compact_unwind)
+ {
+ UnwindPlanSP unwind_plan_sp (new UnwindPlan (lldb::eRegisterKindGeneric));
+ if (compact_unwind->GetUnwindPlan (target, current_pc, *unwind_plan_sp))
{
- m_unwind_plan_call_site_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
- if (!eh_frame->GetUnwindPlan (current_pc, *m_unwind_plan_call_site_sp))
- m_unwind_plan_call_site_sp.reset();
+ m_unwind_plan_compact_unwind.push_back (unwind_plan_sp);
+ return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact unwind plans for one func
}
}
}
- return m_unwind_plan_call_site_sp;
+ return UnwindPlanSP();
}
UnwindPlanSP
-FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int current_offset)
+FuncUnwinders::GetEHFrameUnwindPlan (Target &target, int current_offset)
{
- // Lock the mutex to ensure we can always give out the most appropriate
- // information. We want to make sure if someone requests an unwind
- // plan, that they get one and don't run into a race condition where one
- // thread has started to create the unwind plan and has put it into
- // the unique pointer member variable, and have another thread enter this function
- // and return the partially filled pointer contained in the unique pointer.
- // We also want to make sure that we lock out other unwind plans from
- // being accessed until this one is done creating itself in case someone
- // had some code like:
- // UnwindPlan *best_unwind_plan = ...GetUnwindPlanAtCallSite (...)
- // if (best_unwind_plan == NULL)
- // best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
- Mutex::Locker locker (m_mutex);
- if (m_tried_unwind_at_non_call_site == false && m_unwind_plan_non_call_site_sp.get() == nullptr)
+ if (m_unwind_plan_eh_frame_sp.get() || m_tried_unwind_plan_eh_frame)
+ return m_unwind_plan_eh_frame_sp;
+
+ Mutex::Locker lock (m_mutex);
+ m_tried_unwind_plan_eh_frame = true;
+ if (m_range.GetBaseAddress().IsValid())
{
- UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
- 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 (target.GetArchitecture().GetCore() == ArchSpec::eCore_x86_32_i386
- || target.GetArchitecture().GetCore() == ArchSpec::eCore_x86_64_x86_64
- || target.GetArchitecture().GetCore() == ArchSpec::eCore_x86_64_x86_64h)
+ m_unwind_plan_eh_frame_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ if (!eh_frame->GetUnwindPlan (current_pc, *m_unwind_plan_eh_frame_sp))
+ m_unwind_plan_eh_frame_sp.reset();
+ }
+ }
+ return m_unwind_plan_eh_frame_sp;
+}
+
+UnwindPlanSP
+FuncUnwinders::GetEHFrameAugmentedUnwindPlan (Target &target, Thread &thread, int current_offset)
+{
+ if (m_unwind_plan_eh_frame_augmented_sp.get() || m_tried_unwind_plan_eh_frame_augmented)
+ return m_unwind_plan_eh_frame_augmented_sp;
+
+ // Only supported on x86 architectures where we get eh_frame from the compiler that describes
+ // the prologue instructions perfectly, and sometimes the epilogue instructions too.
+ if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386
+ && target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64
+ && target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h)
+ {
+ m_tried_unwind_plan_eh_frame_augmented = true;
+ return m_unwind_plan_eh_frame_augmented_sp;
+ }
+
+ Mutex::Locker lock (m_mutex);
+ m_tried_unwind_plan_eh_frame_augmented = true;
+
+ if (m_range.GetBaseAddress().IsValid())
+ {
+ 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)
+ {
+ 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))
{
- // For 0th frame on i386 & x86_64, we fetch eh_frame and try using assembly profiler
- // to augment it into asynchronous unwind table.
- GetUnwindPlanAtCallSite(current_offset);
- if (m_unwind_plan_call_site_sp) {
- UnwindPlan* plan = new UnwindPlan (*m_unwind_plan_call_site_sp);
- if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite (m_range, thread, *plan)) {
- m_unwind_plan_non_call_site_sp.reset (plan);
- return m_unwind_plan_non_call_site_sp;
+ m_unwind_plan_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();
+ }
}
+ }
+ }
+ return m_unwind_plan_eh_frame_augmented_sp;
+}
+
+
+UnwindPlanSP
+FuncUnwinders::GetAssemblyUnwindPlan (Target &target, Thread &thread, int current_offset)
+{
+ if (m_unwind_plan_assembly_sp.get() || m_tried_unwind_plan_assembly)
+ return m_unwind_plan_assembly_sp;
- m_unwind_plan_non_call_site_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
- if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_plan_non_call_site_sp))
- m_unwind_plan_non_call_site_sp.reset();
+ Mutex::Locker lock (m_mutex);
+ m_tried_unwind_plan_assembly = true;
+
+ UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
+ if (assembly_profiler_sp)
+ {
+ m_unwind_plan_assembly_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_plan_assembly_sp))
+ {
+ m_unwind_plan_assembly_sp.reset();
}
}
- return m_unwind_plan_non_call_site_sp;
+ return m_unwind_plan_assembly_sp;
+}
+
+
+UnwindPlanSP
+FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int current_offset)
+{
+ UnwindPlanSP non_call_site_unwindplan_sp = GetEHFrameAugmentedUnwindPlan (target, thread, current_offset);
+ if (non_call_site_unwindplan_sp.get() == nullptr)
+ {
+ non_call_site_unwindplan_sp = GetAssemblyUnwindPlan (target, thread, current_offset);
+ }
+ return non_call_site_unwindplan_sp;
}
UnwindPlanSP
FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
{
- // Lock the mutex to ensure we can always give out the most appropriate
- // information. We want to make sure if someone requests an unwind
- // plan, that they get one and don't run into a race condition where one
- // thread has started to create the unwind plan and has put it into
- // the unique pointer member variable, and have another thread enter this function
- // and return the partially filled pointer contained in the unique pointer.
- // We also want to make sure that we lock out other unwind plans from
- // being accessed until this one is done creating itself in case someone
- // had some code like:
- // UnwindPlan *best_unwind_plan = ...GetUnwindPlanAtCallSite (...)
- // if (best_unwind_plan == NULL)
- // best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
+ if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast)
+ return m_unwind_plan_fast_sp;
+
Mutex::Locker locker (m_mutex);
- if (m_tried_unwind_fast == false && m_unwind_plan_fast_sp.get() == nullptr)
+ m_tried_unwind_fast = true;
+
+ UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
+ if (assembly_profiler_sp)
{
- m_tried_unwind_fast = true;
- UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
- if (assembly_profiler_sp)
+ m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ if (!assembly_profiler_sp->GetFastUnwindPlan (m_range, thread, *m_unwind_plan_fast_sp))
{
- m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
- if (!assembly_profiler_sp->GetFastUnwindPlan (m_range, thread, *m_unwind_plan_fast_sp))
- m_unwind_plan_fast_sp.reset();
+ m_unwind_plan_fast_sp.reset();
}
}
return m_unwind_plan_fast_sp;
@@ -171,32 +239,23 @@ FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
UnwindPlanSP
FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread)
{
- // Lock the mutex to ensure we can always give out the most appropriate
- // information. We want to make sure if someone requests an unwind
- // plan, that they get one and don't run into a race condition where one
- // thread has started to create the unwind plan and has put it into
- // the unique pointer member variable, and have another thread enter this function
- // and return the partially filled pointer contained in the unique pointer.
- // We also want to make sure that we lock out other unwind plans from
- // being accessed until this one is done creating itself in case someone
- // had some code like:
- // UnwindPlan *best_unwind_plan = ...GetUnwindPlanAtCallSite (...)
- // if (best_unwind_plan == NULL)
- // best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
+ if (m_unwind_plan_arch_default_sp.get() || m_tried_unwind_arch_default)
+ return m_unwind_plan_arch_default_sp;
+
Mutex::Locker locker (m_mutex);
- if (m_tried_unwind_arch_default == false && m_unwind_plan_arch_default_sp.get() == nullptr)
+ m_tried_unwind_arch_default = true;
+
+ Address current_pc;
+ ProcessSP process_sp (thread.CalculateProcess());
+ if (process_sp)
{
- m_tried_unwind_arch_default = true;
- Address current_pc;
- ProcessSP process_sp (thread.CalculateProcess());
- if (process_sp)
+ ABI *abi = process_sp->GetABI().get();
+ if (abi)
{
- ABI *abi = process_sp->GetABI().get();
- if (abi)
+ m_unwind_plan_arch_default_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ if (!abi->CreateDefaultUnwindPlan(*m_unwind_plan_arch_default_sp))
{
- m_unwind_plan_arch_default_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
- if (m_unwind_plan_arch_default_sp)
- abi->CreateDefaultUnwindPlan(*m_unwind_plan_arch_default_sp);
+ m_unwind_plan_arch_default_sp.reset();
}
}
}
@@ -207,32 +266,23 @@ FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread)
UnwindPlanSP
FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry (Thread& thread)
{
- // Lock the mutex to ensure we can always give out the most appropriate
- // information. We want to make sure if someone requests an unwind
- // plan, that they get one and don't run into a race condition where one
- // thread has started to create the unwind plan and has put it into
- // the unique pointer member variable, and have another thread enter this function
- // and return the partially filled pointer contained in the unique pointer.
- // We also want to make sure that we lock out other unwind plans from
- // being accessed until this one is done creating itself in case someone
- // had some code like:
- // UnwindPlan *best_unwind_plan = ...GetUnwindPlanAtCallSite (...)
- // if (best_unwind_plan == NULL)
- // best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
+ if (m_unwind_plan_arch_default_at_func_entry_sp.get() || m_tried_unwind_arch_default_at_func_entry)
+ return m_unwind_plan_arch_default_at_func_entry_sp;
+
Mutex::Locker locker (m_mutex);
- if (m_tried_unwind_arch_default_at_func_entry == false && m_unwind_plan_arch_default_at_func_entry_sp.get() == nullptr)
+ m_tried_unwind_arch_default_at_func_entry = true;
+
+ Address current_pc;
+ ProcessSP process_sp (thread.CalculateProcess());
+ if (process_sp)
{
- m_tried_unwind_arch_default_at_func_entry = true;
- Address current_pc;
- ProcessSP process_sp (thread.CalculateProcess());
- if (process_sp)
+ ABI *abi = process_sp->GetABI().get();
+ if (abi)
{
- ABI *abi = process_sp->GetABI().get();
- if (abi)
+ m_unwind_plan_arch_default_at_func_entry_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ if (!abi->CreateFunctionEntryUnwindPlan(*m_unwind_plan_arch_default_at_func_entry_sp))
{
- m_unwind_plan_arch_default_at_func_entry_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
- if (m_unwind_plan_arch_default_at_func_entry_sp)
- abi->CreateFunctionEntryUnwindPlan(*m_unwind_plan_arch_default_at_func_entry_sp);
+ m_unwind_plan_arch_default_at_func_entry_sp.reset();
}
}
}
@@ -246,10 +296,11 @@ FuncUnwinders::GetFirstNonPrologueInsn (Target& target)
{
if (m_first_non_prologue_insn.IsValid())
return m_first_non_prologue_insn;
+
+ Mutex::Locker locker (m_mutex);
ExecutionContext exe_ctx (target.shared_from_this(), false);
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
if (assembly_profiler_sp)
- if (assembly_profiler_sp)
assembly_profiler_sp->FirstNonPrologueInsn (m_range, exe_ctx, m_first_non_prologue_insn);
return m_first_non_prologue_insn;
}
@@ -260,16 +311,6 @@ FuncUnwinders::GetFunctionStartAddress () const
return m_range.GetBaseAddress();
}
-void
-FuncUnwinders::InvalidateNonCallSiteUnwindPlan (lldb_private::Thread& thread)
-{
- UnwindPlanSP arch_default = GetUnwindPlanArchitectureDefault (thread);
- if (arch_default && m_tried_unwind_at_call_site)
- {
- m_unwind_plan_call_site_sp = arch_default;
- }
-}
-
lldb::UnwindAssemblySP
FuncUnwinders::GetUnwindAssemblyProfiler ()
{
@@ -281,3 +322,39 @@ FuncUnwinders::GetUnwindAssemblyProfiler ()
}
return assembly_profiler_sp;
}
+
+Address
+FuncUnwinders::GetLSDAAddress (Target &target)
+{
+ Address lsda_addr;
+
+ UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, -1);
+ if (unwind_plan_sp.get() == nullptr)
+ {
+ unwind_plan_sp = GetCompactUnwindUnwindPlan (target, -1);
+ }
+ if (unwind_plan_sp.get() && unwind_plan_sp->GetLSDAAddress().IsValid())
+ {
+ lsda_addr = unwind_plan_sp->GetLSDAAddress();
+ }
+ return lsda_addr;
+}
+
+
+Address
+FuncUnwinders::GetPersonalityRoutinePtrAddress (Target &target)
+{
+ Address personality_addr;
+
+ UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, -1);
+ if (unwind_plan_sp.get() == nullptr)
+ {
+ unwind_plan_sp = GetCompactUnwindUnwindPlan (target, -1);
+ }
+ if (unwind_plan_sp.get() && unwind_plan_sp->GetPersonalityFunctionPtr().IsValid())
+ {
+ personality_addr = unwind_plan_sp->GetPersonalityFunctionPtr();
+ }
+
+ return personality_addr;
+}
diff --git a/source/Symbol/LineTable.cpp b/source/Symbol/LineTable.cpp
index 4b4e33b2b0e9..92b243d80a91 100644
--- a/source/Symbol/LineTable.cpp
+++ b/source/Symbol/LineTable.cpp
@@ -562,7 +562,6 @@ LineTable::LinkLineTable (const FileRangeMap &file_range_map)
// Append the sequence since we just terminated the previous one
line_table_ap->InsertSequence (&sequence);
sequence.Clear();
- prev_entry_was_linked = false;
}
// Now link the current entry
diff --git a/source/Symbol/ObjectFile.cpp b/source/Symbol/ObjectFile.cpp
index 11b540071208..c24e83260d4d 100644
--- a/source/Symbol/ObjectFile.cpp
+++ b/source/Symbol/ObjectFile.cpp
@@ -371,6 +371,7 @@ ObjectFile::GetAddressClass (addr_t file_addr)
case eSectionTypeDWARFAppleObjC:
return eAddressClassDebug;
case eSectionTypeEHFrame:
+ case eSectionTypeCompactUnwind:
return eAddressClassRuntime;
case eSectionTypeELFSymbolTable:
case eSectionTypeELFDynamicSymbols:
@@ -458,6 +459,9 @@ ObjectFile::CopyData (lldb::offset_t offset, size_t length, void *dst) const
size_t
ObjectFile::ReadSectionData (const Section *section, lldb::offset_t section_offset, void *dst, size_t dst_len) const
{
+ assert(section);
+ section_offset *= section->GetTargetByteSize();
+
// If some other objectfile owns this data, pass this to them.
if (section->GetObjectFile() != this)
return section->GetObjectFile()->ReadSectionData (section, section_offset, dst, dst_len);
@@ -555,8 +559,6 @@ ObjectFile::MemoryMapSectionData (const Section *section, DataExtractor& section
// The object file now contains a full mmap'ed copy of the object file data, so just use this
return GetData(section->GetFileOffset(), section->GetFileSize(), section_data);
}
- section_data.Clear();
- return 0;
}
diff --git a/source/Symbol/Symbol.cpp b/source/Symbol/Symbol.cpp
index 880519955277..b6ed94610b0a 100644
--- a/source/Symbol/Symbol.cpp
+++ b/source/Symbol/Symbol.cpp
@@ -626,7 +626,7 @@ Symbol::ResolveCallableAddress(Target &target) const
Address func_so_addr;
- bool is_indirect;
+ bool is_indirect = IsIndirect();
if (GetType() == eSymbolTypeReExported)
{
Symbol *reexported_symbol = ResolveReExportedSymbol(target);
diff --git a/source/Symbol/SymbolContext.cpp b/source/Symbol/SymbolContext.cpp
index 0e390dd08c5f..129f4def0067 100644
--- a/source/Symbol/SymbolContext.cpp
+++ b/source/Symbol/SymbolContext.cpp
@@ -128,7 +128,8 @@ SymbolContext::DumpStopContext
const Address &addr,
bool show_fullpaths,
bool show_module,
- bool show_inlined_frames
+ bool show_inlined_frames,
+ bool show_function_arguments
) const
{
bool dumped_something = false;
@@ -146,7 +147,12 @@ SymbolContext::DumpStopContext
{
SymbolContext inline_parent_sc;
Address inline_parent_addr;
- if (function->GetMangled().GetName())
+ if (show_function_arguments == false && function->GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments))
+ {
+ dumped_something = true;
+ function->GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments).Dump(s);
+ }
+ else if (function->GetMangled().GetName())
{
dumped_something = true;
function->GetMangled().GetName().Dump(s);
@@ -188,7 +194,7 @@ SymbolContext::DumpStopContext
{
s->EOL();
s->Indent();
- return inline_parent_sc.DumpStopContext (s, exe_scope, inline_parent_addr, show_fullpaths, show_module, show_inlined_frames);
+ return inline_parent_sc.DumpStopContext (s, exe_scope, inline_parent_addr, show_fullpaths, show_module, show_inlined_frames, show_function_arguments);
}
}
else
diff --git a/source/Symbol/Type.cpp b/source/Symbol/Type.cpp
index 4eb538fb1352..42b76590aaea 100644
--- a/source/Symbol/Type.cpp
+++ b/source/Symbol/Type.cpp
@@ -31,6 +31,7 @@
#include "llvm/ADT/StringRef.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
using namespace lldb;
using namespace lldb_private;
@@ -1291,6 +1292,117 @@ TypeImpl::GetDescription (lldb_private::Stream &strm,
return true;
}
+TypeMemberFunctionImpl&
+TypeMemberFunctionImpl::operator = (const TypeMemberFunctionImpl& rhs)
+{
+ if (this != &rhs)
+ {
+ m_type = rhs.m_type;
+ m_objc_method_decl = rhs.m_objc_method_decl;
+ m_name = rhs.m_name;
+ m_kind = rhs.m_kind;
+ }
+ return *this;
+}
+
+bool
+TypeMemberFunctionImpl::IsValid ()
+{
+ return m_type.IsValid() && m_kind != lldb::eMemberFunctionKindUnknown;
+}
+
+ConstString
+TypeMemberFunctionImpl::GetName () const
+{
+ return m_name;
+}
+
+ClangASTType
+TypeMemberFunctionImpl::GetType () const
+{
+ return m_type;
+}
+
+lldb::MemberFunctionKind
+TypeMemberFunctionImpl::GetKind () const
+{
+ return m_kind;
+}
+
+std::string
+TypeMemberFunctionImpl::GetPrintableTypeName ()
+{
+ if (m_type)
+ return m_type.GetTypeName().AsCString("<unknown>");
+ if (m_objc_method_decl)
+ {
+ if (m_objc_method_decl->getClassInterface())
+ {
+ return m_objc_method_decl->getClassInterface()->getName();
+ }
+ }
+ return "<unknown>";
+}
+
+bool
+TypeMemberFunctionImpl::GetDescription (Stream& stream)
+{
+ switch (m_kind) {
+ case lldb::eMemberFunctionKindUnknown:
+ return false;
+ case lldb::eMemberFunctionKindConstructor:
+ stream.Printf("constructor for %s", GetPrintableTypeName().c_str());
+ break;
+ case lldb::eMemberFunctionKindDestructor:
+ stream.Printf("destructor for %s", GetPrintableTypeName().c_str());
+ break;
+ case lldb::eMemberFunctionKindInstanceMethod:
+ stream.Printf("instance method %s of type %s",
+ m_name.AsCString(),
+ GetPrintableTypeName().c_str());
+ break;
+ case lldb::eMemberFunctionKindStaticMethod:
+ stream.Printf("static method %s of type %s",
+ m_name.AsCString(),
+ GetPrintableTypeName().c_str());
+ break;
+ }
+ return true;
+}
+
+ClangASTType
+TypeMemberFunctionImpl::GetReturnType () const
+{
+ if (m_type)
+ return m_type.GetFunctionReturnType();
+ if (m_objc_method_decl)
+ return ClangASTType(&m_objc_method_decl->getASTContext(),m_objc_method_decl->getReturnType().getAsOpaquePtr());
+ return ClangASTType();
+}
+
+size_t
+TypeMemberFunctionImpl::GetNumArguments () const
+{
+ if (m_type)
+ return m_type.GetNumberOfFunctionArguments();
+ if (m_objc_method_decl)
+ return m_objc_method_decl->param_size();
+ return 0;
+}
+
+ClangASTType
+TypeMemberFunctionImpl::GetArgumentAtIndex (size_t idx) const
+{
+ if (m_type)
+ return m_type.GetFunctionArgumentAtIndex (idx);
+ if (m_objc_method_decl)
+ {
+ if (idx < m_objc_method_decl->param_size())
+ return ClangASTType(&m_objc_method_decl->getASTContext(), m_objc_method_decl->parameters()[idx]->getOriginalType().getAsOpaquePtr());
+ }
+ return ClangASTType();
+}
+
TypeEnumMemberImpl::TypeEnumMemberImpl (const clang::EnumConstantDecl* enum_member_decl,
const lldb_private::ClangASTType& integer_type) :
m_integer_type_sp(),
diff --git a/source/Symbol/UnwindPlan.cpp b/source/Symbol/UnwindPlan.cpp
index ff0468e314d8..87d0f49421c5 100644
--- a/source/Symbol/UnwindPlan.cpp
+++ b/source/Symbol/UnwindPlan.cpp
@@ -153,6 +153,7 @@ UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_pla
void
UnwindPlan::Row::Clear ()
{
+ m_cfa_type = CFAIsRegisterPlusOffset;
m_offset = 0;
m_cfa_reg_num = LLDB_INVALID_REGNUM;
m_cfa_offset = 0;
@@ -167,7 +168,7 @@ UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread,
if (base_addr != LLDB_INVALID_ADDRESS)
s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
else
- s.Printf ("0x%8.8" PRIx64 ": CFA=", GetOffset());
+ s.Printf ("%4" PRId64 ": CFA=", GetOffset());
if (reg_info)
s.Printf ("%s", reg_info->name);
@@ -189,10 +190,11 @@ UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread,
}
UnwindPlan::Row::Row() :
- m_offset(0),
- m_cfa_reg_num(LLDB_INVALID_REGNUM),
- m_cfa_offset(0),
- m_register_locations()
+ m_offset (0),
+ m_cfa_type (CFAIsRegisterPlusOffset),
+ m_cfa_reg_num (LLDB_INVALID_REGNUM),
+ m_cfa_offset (0),
+ m_register_locations ()
{
}
@@ -209,6 +211,16 @@ UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLoc
}
void
+UnwindPlan::Row::RemoveRegisterInfo (uint32_t reg_num)
+{
+ collection::const_iterator pos = m_register_locations.find(reg_num);
+ if (pos != m_register_locations.end())
+ {
+ m_register_locations.erase(pos);
+ }
+}
+
+void
UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
{
m_register_locations[reg_num] = register_location;
@@ -301,6 +313,23 @@ 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;
}
@@ -449,6 +478,44 @@ UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
{
s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
}
+ if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid())
+ {
+ TargetSP target_sp(thread->CalculateTarget());
+ addr_t lsda_load_addr = m_lsda_address.GetLoadAddress (target_sp.get());
+ addr_t personality_func_load_addr = m_personality_func_addr.GetLoadAddress (target_sp.get());
+
+ if (lsda_load_addr != LLDB_INVALID_ADDRESS && personality_func_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ s.Printf("LSDA address 0x%" PRIx64 ", personality routine is at address 0x%" PRIx64 "\n",
+ lsda_load_addr, personality_func_load_addr);
+ }
+ }
+ s.Printf ("This UnwindPlan is sourced from the compiler: ");
+ switch (m_plan_is_sourced_from_compiler)
+ {
+ case eLazyBoolYes:
+ s.Printf ("yes.\n");
+ break;
+ case eLazyBoolNo:
+ s.Printf ("no.\n");
+ break;
+ case eLazyBoolCalculate:
+ s.Printf ("not specified.\n");
+ break;
+ }
+ s.Printf ("This UnwindPlan is valid at all instruction locations: ");
+ switch (m_plan_is_valid_at_all_instruction_locations)
+ {
+ case eLazyBoolYes:
+ s.Printf ("yes.\n");
+ break;
+ case eLazyBoolNo:
+ s.Printf ("no.\n");
+ break;
+ case eLazyBoolCalculate:
+ s.Printf ("not specified.\n");
+ break;
+ }
if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
{
s.PutCString ("Address range of this UnwindPlan: ");
diff --git a/source/Symbol/UnwindTable.cpp b/source/Symbol/UnwindTable.cpp
index df9f5b932565..90b33a69a789 100644
--- a/source/Symbol/UnwindTable.cpp
+++ b/source/Symbol/UnwindTable.cpp
@@ -17,6 +17,7 @@
#include "lldb/Symbol/FuncUnwinders.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/CompactUnwindInfo.h"
// There is one UnwindTable object per ObjectFile.
// It contains a list of Unwind objects -- one per function, populated lazily -- for the ObjectFile.
@@ -30,7 +31,8 @@ UnwindTable::UnwindTable (ObjectFile& objfile) :
m_unwinds (),
m_initialized (false),
m_mutex (),
- m_eh_frame (nullptr)
+ m_eh_frame (nullptr),
+ m_compact_unwind (nullptr)
{
}
@@ -56,6 +58,11 @@ UnwindTable::Initialize ()
{
m_eh_frame = new DWARFCallFrameInfo(m_object_file, sect, eRegisterKindGCC, true);
}
+ sect = sl->FindSectionByType (eSectionTypeCompactUnwind, true);
+ if (sect.get())
+ {
+ m_compact_unwind = new CompactUnwindInfo(m_object_file, sect);
+ }
}
m_initialized = true;
@@ -154,6 +161,13 @@ UnwindTable::GetEHFrameInfo ()
return m_eh_frame;
}
+CompactUnwindInfo *
+UnwindTable::GetCompactUnwindInfo ()
+{
+ Initialize();
+ return m_compact_unwind;
+}
+
bool
UnwindTable::GetArchitecture (lldb_private::ArchSpec &arch)
{
diff --git a/source/Symbol/Variable.cpp b/source/Symbol/Variable.cpp
index e6a9b027fc13..b1a60f6b4a24 100644
--- a/source/Symbol/Variable.cpp
+++ b/source/Symbol/Variable.cpp
@@ -174,13 +174,15 @@ Variable::DumpDeclaration (Stream *s, bool show_fullpaths, bool show_module)
sc.block = nullptr;
sc.line_entry.Clear();
bool show_inlined_frames = false;
+ const bool show_function_arguments = true;
dumped_declaration_info = sc.DumpStopContext (s,
nullptr,
Address(),
show_fullpaths,
show_module,
- show_inlined_frames);
+ show_inlined_frames,
+ show_function_arguments);
if (sc.function)
s->PutChar(':');
diff --git a/source/Target/CPPLanguageRuntime.cpp b/source/Target/CPPLanguageRuntime.cpp
index f5b7f7fc41a6..f048c6706a9b 100644
--- a/source/Target/CPPLanguageRuntime.cpp
+++ b/source/Target/CPPLanguageRuntime.cpp
@@ -11,6 +11,8 @@
#include <string.h>
+#include "llvm/ADT/StringRef.h"
+
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/Target/ExecutionContext.h"
@@ -190,30 +192,17 @@ CPPLanguageRuntime::IsCPPMangledName (const char *name)
}
bool
-CPPLanguageRuntime::StripNamespacesFromVariableName (const char *name, const char *&base_name_start, const char *&base_name_end)
+CPPLanguageRuntime::ExtractContextAndIdentifier (const char *name, llvm::StringRef &context, llvm::StringRef &identifier)
{
- if (base_name_end == NULL)
- base_name_end = name + strlen (name);
-
- const char *last_colon = strrchr (name, ':');
-
- if (last_colon == NULL)
- {
- base_name_start = name;
- return true;
- }
-
- // Can't have a C++ name that begins with a single ':', nor contains an internal single ':'
- if (last_colon == name)
- return false;
- else if (last_colon[-1] != ':')
- return false;
- else
+ static RegularExpression g_basename_regex("^(([A-Za-z_][A-Za-z_0-9]*::)*)([A-Za-z_][A-Za-z_0-9]*)$");
+ RegularExpression::Match match(4);
+ if (g_basename_regex.Execute (name, &match))
{
- // FIXME: should check if there is
- base_name_start = last_colon + 1;
+ match.GetMatchAtIndex(name, 1, context);
+ match.GetMatchAtIndex(name, 3, identifier);
return true;
}
+ return false;
}
uint32_t
@@ -282,6 +271,7 @@ ReverseFindMatchingChars (const llvm::StringRef &s,
return false;
}
+
void
CPPLanguageRuntime::MethodName::Parse()
{
@@ -306,6 +296,7 @@ CPPLanguageRuntime::MethodName::Parse()
if (arg_start > 0)
{
size_t basename_end = arg_start;
+ size_t context_start = 0;
size_t context_end = llvm::StringRef::npos;
if (basename_end > 0 && full[basename_end-1] == '>')
{
@@ -314,16 +305,35 @@ CPPLanguageRuntime::MethodName::Parse()
size_t template_start, template_end;
llvm::StringRef lt_gt("<>", 2);
if (ReverseFindMatchingChars (full, lt_gt, template_start, template_end, basename_end))
+ {
context_end = full.rfind(':', template_start);
+ if (context_end == llvm::StringRef::npos)
+ {
+ // Check for templated functions that include return type like:
+ // 'void foo<Int>()'
+ context_end = full.rfind(' ', template_start);
+ if (context_end != llvm::StringRef::npos)
+ {
+ context_start = context_end;
+ }
+ }
+ }
+ else
+ {
+ context_end = full.rfind(':', basename_end);
+ }
}
- if (context_end == llvm::StringRef::npos)
+ else if (context_end == llvm::StringRef::npos)
+ {
context_end = full.rfind(':', basename_end);
+ }
if (context_end == llvm::StringRef::npos)
m_basename = full.substr(0, basename_end);
else
{
- m_context = full.substr(0, context_end - 1);
+ if (context_start < context_end)
+ m_context = full.substr(context_start, context_end - 1);
const size_t basename_begin = context_end + 1;
m_basename = full.substr(basename_begin, basename_end - basename_begin);
}
@@ -343,6 +353,30 @@ CPPLanguageRuntime::MethodName::Parse()
// printf (" arguments = '%s'\n", m_arguments.str().c_str());
// if (!m_qualifiers.empty())
// printf ("qualifiers = '%s'\n", m_qualifiers.str().c_str());
+
+ // Make sure we have a valid C++ basename with optional template args
+ static RegularExpression g_identifier_regex("^~?([A-Za-z_][A-Za-z_0-9]*)(<.*>)?$");
+ std::string basename_str(m_basename.str());
+ bool basename_is_valid = g_identifier_regex.Execute (basename_str.c_str(), NULL);
+ if (!basename_is_valid)
+ {
+ // Check for C++ operators
+ if (m_basename.startswith("operator"))
+ {
+ static RegularExpression g_operator_regex("^(operator)( ?)([A-Za-z_][A-Za-z_0-9]*|\\(\\)|\\[\\]|[\\^<>=!\\/*+-]+)(<.*>)?(\\[\\])?$");
+ basename_is_valid = g_operator_regex.Execute(basename_str.c_str(), NULL);
+ }
+ }
+ if (!basename_is_valid)
+ {
+ // The C++ basename doesn't match our regular expressions so this can't
+ // be a valid C++ method, clear everything out and indicate an error
+ m_context = llvm::StringRef();
+ m_basename = llvm::StringRef();
+ m_arguments = llvm::StringRef();
+ m_qualifiers = llvm::StringRef();
+ m_parse_error = true;
+ }
}
else
{
diff --git a/source/Target/FileAction.cpp b/source/Target/FileAction.cpp
index 18b039998bc7..8611ff5f2d2c 100644
--- a/source/Target/FileAction.cpp
+++ b/source/Target/FileAction.cpp
@@ -13,6 +13,7 @@
#include "lldb/Host/Windows/win32.h" // For O_NOCTTY
#endif
+#include "lldb/Core/Stream.h"
#include "lldb/Target/FileAction.h"
using namespace lldb_private;
@@ -21,11 +22,11 @@ using namespace lldb_private;
// FileAction member functions
//----------------------------------------------------------------------------
-FileAction::FileAction()
- : m_action(eFileActionNone)
- , m_fd(-1)
- , m_arg(-1)
- , m_path()
+FileAction::FileAction() :
+ m_action(eFileActionNone),
+ m_fd(-1),
+ m_arg(-1),
+ m_path()
{
}
@@ -93,3 +94,24 @@ FileAction::Duplicate(int fd, int dup_fd)
}
return m_fd >= 0;
}
+
+void
+FileAction::Dump(Stream &stream) const
+{
+ stream.PutCString("file action: ");
+ switch (m_action)
+ {
+ case eFileActionClose:
+ stream.Printf("close fd %d", m_fd);
+ break;
+ case eFileActionDuplicate:
+ stream.Printf("duplicate fd %d to %d", m_fd, m_arg);
+ break;
+ case eFileActionNone:
+ 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);
+ break;
+ }
+}
diff --git a/source/Target/InstrumentationRuntime.cpp b/source/Target/InstrumentationRuntime.cpp
new file mode 100644
index 000000000000..b3b2393b0234
--- /dev/null
+++ b/source/Target/InstrumentationRuntime.cpp
@@ -0,0 +1,48 @@
+//===-- InstrumentationRuntime.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/InstrumentationRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+InstrumentationRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list, lldb_private::Process *process, InstrumentationRuntimeCollection &runtimes)
+{
+ InstrumentationRuntimeCreateInstance create_callback = NULL;
+ InstrumentationRuntimeGetType get_type_callback;
+ for (uint32_t idx = 0; ; ++idx)
+ {
+ create_callback = PluginManager::GetInstrumentationRuntimeCreateCallbackAtIndex(idx);
+ if (create_callback == NULL)
+ break;
+ get_type_callback = PluginManager::GetInstrumentationRuntimeGetTypeCallbackAtIndex(idx);
+ InstrumentationRuntimeType type = get_type_callback();
+
+ InstrumentationRuntimeCollection::iterator pos;
+ pos = runtimes.find (type);
+ if (pos == runtimes.end()) {
+ runtimes[type] = create_callback(process->shared_from_this());
+ }
+ }
+}
+
+void
+InstrumentationRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list)
+{
+}
+
+bool
+InstrumentationRuntime::IsActive()
+{
+ return false;
+}
diff --git a/source/Target/InstrumentationRuntimeStopInfo.cpp b/source/Target/InstrumentationRuntimeStopInfo.cpp
new file mode 100644
index 000000000000..cdbf93b5f720
--- /dev/null
+++ b/source/Target/InstrumentationRuntimeStopInfo.cpp
@@ -0,0 +1,36 @@
+//===-- InstrumentationRuntimeStopInfo.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/InstrumentationRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+InstrumentationRuntimeStopInfo::InstrumentationRuntimeStopInfo(Thread &thread, std::string description, StructuredData::ObjectSP additional_data) :
+ StopInfo(thread, 0)
+{
+ m_extended_info = additional_data;
+ m_description = description;
+}
+
+const char *
+InstrumentationRuntimeStopInfo::GetDescription ()
+{
+ return m_description.c_str();
+}
+
+StopInfoSP
+InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData (Thread &thread, std::string description, StructuredData::ObjectSP additionalData)
+{
+ return StopInfoSP(new InstrumentationRuntimeStopInfo(thread, description, additionalData));
+}
diff --git a/source/Target/LanguageRuntime.cpp b/source/Target/LanguageRuntime.cpp
index 9d48d8b2de7f..358bffee3a4d 100644
--- a/source/Target/LanguageRuntime.cpp
+++ b/source/Target/LanguageRuntime.cpp
@@ -10,6 +10,7 @@
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/SearchFilter.h"
using namespace lldb;
using namespace lldb_private;
@@ -19,17 +20,22 @@ class ExceptionSearchFilter : public SearchFilter
{
public:
ExceptionSearchFilter (const lldb::TargetSP &target_sp,
- lldb::LanguageType language) :
+ lldb::LanguageType language,
+ bool update_module_list = true) :
SearchFilter (target_sp),
m_language (language),
m_language_runtime (NULL),
m_filter_sp ()
{
- UpdateModuleListIfNeeded ();
+ if (update_module_list)
+ UpdateModuleListIfNeeded ();
}
-
- virtual bool
- ModulePasses (const lldb::ModuleSP &module_sp)
+
+ virtual
+ ~ExceptionSearchFilter() {};
+
+ bool
+ ModulePasses (const lldb::ModuleSP &module_sp) override
{
UpdateModuleListIfNeeded ();
if (m_filter_sp)
@@ -37,8 +43,8 @@ public:
return false;
}
- virtual bool
- ModulePasses (const FileSpec &spec)
+ bool
+ ModulePasses (const FileSpec &spec) override
{
UpdateModuleListIfNeeded ();
if (m_filter_sp)
@@ -47,16 +53,16 @@ public:
}
- virtual void
- Search (Searcher &searcher)
+ void
+ Search (Searcher &searcher) override
{
UpdateModuleListIfNeeded ();
if (m_filter_sp)
m_filter_sp->Search (searcher);
}
- virtual void
- GetDescription (Stream *s)
+ void
+ GetDescription (Stream *s) override
{
UpdateModuleListIfNeeded ();
if (m_filter_sp)
@@ -68,6 +74,12 @@ protected:
LanguageRuntime *m_language_runtime;
SearchFilterSP m_filter_sp;
+ SearchFilterSP
+ DoCopyForBreakpoint(Breakpoint &breakpoint) override
+ {
+ return SearchFilterSP(new ExceptionSearchFilter(TargetSP(), m_language, false));
+ }
+
void
UpdateModuleListIfNeeded ()
{
@@ -124,11 +136,11 @@ public:
{
}
- virtual Searcher::CallbackReturn
+ Searcher::CallbackReturn
SearchCallback (SearchFilter &filter,
SymbolContext &context,
Address *addr,
- bool containing)
+ bool containing) override
{
if (SetActualResolver())
@@ -137,8 +149,8 @@ public:
return eCallbackReturnStop;
}
- virtual Searcher::Depth
- GetDepth ()
+ Searcher::Depth
+ GetDepth () override
{
if (SetActualResolver())
return m_actual_resolver_sp->GetDepth();
@@ -146,8 +158,8 @@ public:
return eDepthTarget;
}
- virtual void
- GetDescription (Stream *s)
+ void
+ GetDescription (Stream *s) override
{
s->Printf ("Exception breakpoint (catch: %s throw: %s)",
m_catch_bp ? "on" : "off",
@@ -163,8 +175,8 @@ public:
s->Printf (" the correct runtime exception handler will be determined when you run");
}
- virtual void
- Dump (Stream *s) const
+ void
+ Dump (Stream *s) const override
{
}
@@ -174,6 +186,12 @@ public:
return V->getResolverID() == BreakpointResolver::ExceptionResolver;
}
protected:
+ BreakpointResolverSP
+ CopyForBreakpoint (Breakpoint &breakpoint) override
+ {
+ return BreakpointResolverSP(new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp));
+ }
+
bool
SetActualResolver()
{
diff --git a/source/Target/Memory.cpp b/source/Target/Memory.cpp
index b212fcd23a45..934bc967b68b 100644
--- a/source/Target/Memory.cpp
+++ b/source/Target/Memory.cpp
@@ -26,7 +26,7 @@ using namespace lldb_private;
//----------------------------------------------------------------------
MemoryCache::MemoryCache(Process &process) :
m_process (process),
- m_cache_line_byte_size (512),
+ m_cache_line_byte_size (process.GetMemoryCacheLineSize()),
m_mutex (Mutex::eMutexTypeRecursive),
m_cache (),
m_invalid_ranges ()
@@ -47,6 +47,7 @@ MemoryCache::Clear(bool clear_invalid_ranges)
m_cache.clear();
if (clear_invalid_ranges)
m_invalid_ranges.Clear();
+ m_cache_line_byte_size = m_process.GetMemoryCacheLineSize();
}
void
@@ -250,7 +251,8 @@ AllocatedBlock::ReserveBlock (uint32_t size)
{
m_offset_to_chunk_size[0] = needed_chunks;
if (log)
- log->Printf ("[1] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", this, size, size, 0, needed_chunks, m_chunk_size);
+ log->Printf("[1] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", (void *)this,
+ size, size, 0, needed_chunks, m_chunk_size);
addr = m_addr;
}
else
@@ -268,7 +270,9 @@ AllocatedBlock::ReserveBlock (uint32_t size)
{
m_offset_to_chunk_size[last_offset] = needed_chunks;
if (log)
- log->Printf ("[2] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - num_chunks %lu", this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
+ log->Printf("[2] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - "
+ "num_chunks %lu",
+ (void *)this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
addr = m_addr + last_offset;
break;
}
@@ -284,7 +288,9 @@ AllocatedBlock::ReserveBlock (uint32_t size)
{
m_offset_to_chunk_size[last_offset] = needed_chunks;
if (log)
- log->Printf ("[3] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - num_chunks %lu", this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
+ log->Printf("[3] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - "
+ "num_chunks %lu",
+ (void *)this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
addr = m_addr + last_offset;
break;
}
@@ -345,7 +351,7 @@ AllocatedBlock::ReserveBlock (uint32_t size)
}
if (log)
- log->Printf ("AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => 0x%16.16" PRIx64, this, size, size, (uint64_t)addr);
+ log->Printf("AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => 0x%16.16" PRIx64, (void *)this, size, size, (uint64_t)addr);
return addr;
}
@@ -362,7 +368,8 @@ AllocatedBlock::FreeBlock (addr_t addr)
}
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
if (log)
- log->Printf ("AllocatedBlock::FreeBlock(%p) (addr = 0x%16.16" PRIx64 ") => %i, num_chunks: %lu", this, (uint64_t)addr, success, m_offset_to_chunk_size.size());
+ log->Printf("AllocatedBlock::FreeBlock(%p) (addr = 0x%16.16" PRIx64 ") => %i, num_chunks: %lu", (void *)this, (uint64_t)addr,
+ success, m_offset_to_chunk_size.size());
return success;
}
diff --git a/source/Target/MemoryHistory.cpp b/source/Target/MemoryHistory.cpp
new file mode 100644
index 000000000000..b97096b06d76
--- /dev/null
+++ b/source/Target/MemoryHistory.cpp
@@ -0,0 +1,30 @@
+//===-- MemoryHistory.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/MemoryHistory.h"
+
+#include "lldb/Core/PluginManager.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+lldb::MemoryHistorySP
+MemoryHistory::FindPlugin (const ProcessSP process)
+{
+ MemoryHistoryCreateInstance create_callback = NULL;
+
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetMemoryHistoryCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ MemoryHistorySP memory_history_sp (create_callback (process));
+ if (memory_history_sp.get())
+ return memory_history_sp;
+ }
+
+ return MemoryHistorySP();
+}
diff --git a/source/Target/ObjCLanguageRuntime.cpp b/source/Target/ObjCLanguageRuntime.cpp
index 1f2abd876c84..b182407bf68e 100644
--- a/source/Target/ObjCLanguageRuntime.cpp
+++ b/source/Target/ObjCLanguageRuntime.cpp
@@ -603,20 +603,20 @@ ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa)
ClangASTType
-ObjCLanguageRuntime::EncodingToType::RealizeType (const char* name, bool allow_unknownanytype)
+ObjCLanguageRuntime::EncodingToType::RealizeType (const char* name, bool for_expression)
{
if (m_scratch_ast_ctx_ap)
- return RealizeType(*m_scratch_ast_ctx_ap, name, allow_unknownanytype);
+ return RealizeType(*m_scratch_ast_ctx_ap, name, for_expression);
return ClangASTType();
}
ClangASTType
-ObjCLanguageRuntime::EncodingToType::RealizeType (ClangASTContext& ast_ctx, const char* name, bool allow_unknownanytype)
+ObjCLanguageRuntime::EncodingToType::RealizeType (ClangASTContext& ast_ctx, const char* name, bool for_expression)
{
clang::ASTContext *clang_ast = ast_ctx.getASTContext();
if (!clang_ast)
return ClangASTType();
- return RealizeType(*clang_ast, name, allow_unknownanytype);
+ return RealizeType(*clang_ast, name, for_expression);
}
ObjCLanguageRuntime::EncodingToType::~EncodingToType() {}
diff --git a/source/Target/Platform.cpp b/source/Target/Platform.cpp
index fe73be2d05b9..4ebd18b8bfd0 100644
--- a/source/Target/Platform.cpp
+++ b/source/Target/Platform.cpp
@@ -32,26 +32,12 @@ using namespace lldb_private;
// Use a singleton function for g_local_platform_sp to avoid init
// constructors since LLDB is often part of a shared library
static PlatformSP&
-GetDefaultPlatformSP ()
+GetHostPlatformSP ()
{
- static PlatformSP g_default_platform_sp;
- return g_default_platform_sp;
+ static PlatformSP g_platform_sp;
+ return g_platform_sp;
}
-static Mutex &
-GetConnectedPlatformListMutex ()
-{
- static Mutex g_remote_connected_platforms_mutex (Mutex::eMutexTypeRecursive);
- return g_remote_connected_platforms_mutex;
-}
-static std::vector<PlatformSP> &
-GetConnectedPlatformList ()
-{
- static std::vector<PlatformSP> g_remote_connected_platforms;
- return g_remote_connected_platforms;
-}
-
-
const char *
Platform::GetHostPlatformName ()
{
@@ -69,17 +55,37 @@ Platform::GetHostPlatformName ()
/// or attaching to processes unless another platform is specified.
//------------------------------------------------------------------
PlatformSP
-Platform::GetDefaultPlatform ()
+Platform::GetHostPlatform ()
{
- return GetDefaultPlatformSP ();
+ return GetHostPlatformSP ();
+}
+
+static std::vector<PlatformSP> &
+GetPlatformList()
+{
+ static std::vector<PlatformSP> g_platform_list;
+ return g_platform_list;
+}
+
+static Mutex &
+GetPlatformListMutex ()
+{
+ static Mutex g_mutex(Mutex::eMutexTypeRecursive);
+ return g_mutex;
}
void
-Platform::SetDefaultPlatform (const lldb::PlatformSP &platform_sp)
+Platform::SetHostPlatform (const lldb::PlatformSP &platform_sp)
{
// The native platform should use its static void Platform::Initialize()
// function to register itself as the native platform.
- GetDefaultPlatformSP () = platform_sp;
+ GetHostPlatformSP () = platform_sp;
+
+ if (platform_sp)
+ {
+ Mutex::Locker locker(GetPlatformListMutex ());
+ GetPlatformList().push_back(platform_sp);
+ }
}
Error
@@ -98,36 +104,36 @@ Platform::LocateExecutableScriptingResources (Target *target, Module &module, St
return FileSpecList();
}
-Platform*
-Platform::FindPlugin (Process *process, const ConstString &plugin_name)
-{
- PlatformCreateInstance create_callback = NULL;
- if (plugin_name)
- {
- create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name);
- if (create_callback)
- {
- ArchSpec arch;
- if (process)
- {
- arch = process->GetTarget().GetArchitecture();
- }
- std::unique_ptr<Platform> instance_ap(create_callback(process, &arch));
- if (instance_ap.get())
- return instance_ap.release();
- }
- }
- else
- {
- for (uint32_t idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != NULL; ++idx)
- {
- std::unique_ptr<Platform> instance_ap(create_callback(process, nullptr));
- if (instance_ap.get())
- return instance_ap.release();
- }
- }
- return NULL;
-}
+//PlatformSP
+//Platform::FindPlugin (Process *process, const ConstString &plugin_name)
+//{
+// PlatformCreateInstance create_callback = NULL;
+// if (plugin_name)
+// {
+// create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name);
+// if (create_callback)
+// {
+// ArchSpec arch;
+// if (process)
+// {
+// arch = process->GetTarget().GetArchitecture();
+// }
+// PlatformSP platform_sp(create_callback(process, &arch));
+// if (platform_sp)
+// return platform_sp;
+// }
+// }
+// else
+// {
+// for (uint32_t idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != NULL; ++idx)
+// {
+// PlatformSP platform_sp(create_callback(process, nullptr));
+// if (platform_sp)
+// return platform_sp;
+// }
+// }
+// return PlatformSP();
+//}
Error
Platform::GetSharedModule (const ModuleSpec &module_spec,
@@ -153,21 +159,50 @@ Platform::GetSharedModule (const ModuleSpec &module_spec,
}
PlatformSP
-Platform::Create (const char *platform_name, Error &error)
+Platform::Find (const ConstString &name)
+{
+ if (name)
+ {
+ static ConstString g_host_platform_name ("host");
+ if (name == g_host_platform_name)
+ return GetHostPlatform();
+
+ Mutex::Locker locker(GetPlatformListMutex ());
+ for (const auto &platform_sp : GetPlatformList())
+ {
+ if (platform_sp->GetName() == name)
+ return platform_sp;
+ }
+ }
+ return PlatformSP();
+}
+
+PlatformSP
+Platform::Create (const ConstString &name, Error &error)
{
PlatformCreateInstance create_callback = NULL;
lldb::PlatformSP platform_sp;
- if (platform_name && platform_name[0])
+ if (name)
{
- ConstString const_platform_name (platform_name);
- create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (const_platform_name);
+ static ConstString g_host_platform_name ("host");
+ if (name == g_host_platform_name)
+ return GetHostPlatform();
+
+ create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (name);
if (create_callback)
- platform_sp.reset(create_callback(true, NULL));
+ platform_sp = create_callback(true, NULL);
else
- error.SetErrorStringWithFormat ("unable to find a plug-in for the platform named \"%s\"", platform_name);
+ error.SetErrorStringWithFormat ("unable to find a plug-in for the platform named \"%s\"", name.GetCString());
}
else
error.SetErrorString ("invalid platform name");
+
+ if (platform_sp)
+ {
+ Mutex::Locker locker(GetPlatformListMutex ());
+ GetPlatformList().push_back(platform_sp);
+ }
+
return platform_sp;
}
@@ -178,28 +213,52 @@ Platform::Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &erro
lldb::PlatformSP platform_sp;
if (arch.IsValid())
{
- uint32_t idx;
+ // Scope for locker
+ {
+ // First try exact arch matches across all platforms already created
+ Mutex::Locker locker(GetPlatformListMutex ());
+ for (const auto &platform_sp : GetPlatformList())
+ {
+ if (platform_sp->IsCompatibleArchitecture(arch, true, platform_arch_ptr))
+ return platform_sp;
+ }
+
+ // Next try compatible arch matches across all platforms already created
+ for (const auto &platform_sp : GetPlatformList())
+ {
+ if (platform_sp->IsCompatibleArchitecture(arch, false, platform_arch_ptr))
+ return platform_sp;
+ }
+ }
+
PlatformCreateInstance create_callback;
// First try exact arch matches across all platform plug-ins
- bool exact = true;
+ uint32_t idx;
for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx)
{
if (create_callback)
{
- platform_sp.reset(create_callback(false, &arch));
- if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, exact, platform_arch_ptr))
+ platform_sp = create_callback(false, &arch);
+ if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, true, platform_arch_ptr))
+ {
+ Mutex::Locker locker(GetPlatformListMutex ());
+ GetPlatformList().push_back(platform_sp);
return platform_sp;
+ }
}
}
// Next try compatible arch matches across all platform plug-ins
- exact = false;
for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx)
{
if (create_callback)
{
- platform_sp.reset(create_callback(false, &arch));
- if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, exact, platform_arch_ptr))
+ platform_sp = create_callback(false, &arch);
+ if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, false, platform_arch_ptr))
+ {
+ Mutex::Locker locker(GetPlatformListMutex ());
+ GetPlatformList().push_back(platform_sp);
return platform_sp;
+ }
}
}
}
@@ -211,25 +270,6 @@ Platform::Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &erro
return platform_sp;
}
-uint32_t
-Platform::GetNumConnectedRemotePlatforms ()
-{
- Mutex::Locker locker (GetConnectedPlatformListMutex ());
- return GetConnectedPlatformList().size();
-}
-
-PlatformSP
-Platform::GetConnectedRemotePlatformAtIndex (uint32_t idx)
-{
- PlatformSP platform_sp;
- {
- Mutex::Locker locker (GetConnectedPlatformListMutex ());
- if (idx < GetConnectedPlatformList().size())
- platform_sp = GetConnectedPlatformList ()[idx];
- }
- return platform_sp;
-}
-
//------------------------------------------------------------------
/// Default Constructor
//------------------------------------------------------------------
@@ -422,6 +462,20 @@ Platform::GetOSKernelDescription (std::string &s)
return GetRemoteOSKernelDescription (s);
}
+void
+Platform::AddClangModuleCompilationOptions (std::vector<std::string> &options)
+{
+ std::vector<std::string> default_compilation_options =
+ {
+ "-x", "c++", "-Xclang", "-nostdsysteminc", "-Xclang", "-nostdsysteminc"
+ };
+
+ options.insert(options.end(),
+ default_compilation_options.begin(),
+ default_compilation_options.end());
+}
+
+
ConstString
Platform::GetWorkingDirectory ()
{
@@ -537,11 +591,11 @@ RecurseCopy_Callback (void *baton,
case FileSpec::eFileTypeInvalid:
case FileSpec::eFileTypeOther:
case FileSpec::eFileTypeUnknown:
- default:
rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str());
return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
break;
}
+ llvm_unreachable("Unhandled FileSpec::FileType!");
}
Error
@@ -842,15 +896,13 @@ Platform::SetOSVersion (uint32_t major,
Error
-Platform::ResolveExecutable (const FileSpec &exe_file,
- const ArchSpec &exe_arch,
+Platform::ResolveExecutable (const ModuleSpec &module_spec,
lldb::ModuleSP &exe_module_sp,
const FileSpecList *module_search_paths_ptr)
{
Error error;
- if (exe_file.Exists())
+ if (module_spec.GetFileSpec().Exists())
{
- ModuleSpec module_spec (exe_file, exe_arch);
if (module_spec.GetArchitecture().IsValid())
{
error = ModuleList::GetSharedModule (module_spec,
@@ -864,9 +916,10 @@ Platform::ResolveExecutable (const FileSpec &exe_file,
// No valid architecture was specified, ask the platform for
// the architectures that we should be using (in the correct order)
// and see if we can find a match that way
- for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx)
+ ModuleSpec arch_module_spec(module_spec);
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, arch_module_spec.GetArchitecture()); ++idx)
{
- error = ModuleList::GetSharedModule (module_spec,
+ error = ModuleList::GetSharedModule (arch_module_spec,
exe_module_sp,
module_search_paths_ptr,
NULL,
@@ -880,7 +933,7 @@ Platform::ResolveExecutable (const FileSpec &exe_file,
else
{
error.SetErrorStringWithFormat ("'%s' does not exist",
- exe_file.GetPath().c_str());
+ module_spec.GetFileSpec().GetPath().c_str());
}
return error;
}
@@ -1005,7 +1058,11 @@ Error
Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
{
Error error;
- // Take care of the host case so that each subclass can just
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf ("Platform::%s()", __FUNCTION__);
+
+ // Take care of the host case so that each subclass can just
// call this function to get the host functionality.
if (IsHost())
{
@@ -1018,6 +1075,16 @@ Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug);
const bool first_arg_is_full_shell_command = false;
uint32_t num_resumes = GetResumeCountForLaunchInfo (launch_info);
+ if (log)
+ {
+ const FileSpec &shell = launch_info.GetShell();
+ const char *shell_str = (shell) ? shell.GetPath().c_str() : "<null>";
+ log->Printf ("Platform::%s GetResumeCountForLaunchInfo() returned %" PRIu32 ", shell is '%s'",
+ __FUNCTION__,
+ num_resumes,
+ shell_str);
+ }
+
if (!launch_info.ConvertArgumentsForLaunchingInShell (error,
is_localhost,
will_debug,
@@ -1026,6 +1093,9 @@ Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
return error;
}
+ if (log)
+ log->Printf ("Platform::%s final launch_info resume count: %" PRIu32, __FUNCTION__, launch_info.GetResumeCount ());
+
error = Host::LaunchProcess (launch_info);
}
else
@@ -1037,9 +1107,12 @@ lldb::ProcessSP
Platform::DebugProcess (ProcessLaunchInfo &launch_info,
Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new target, else use existing one
- Listener &listener,
Error &error)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf ("Platform::%s entered (target %p)", __FUNCTION__, static_cast<void*>(target));
+
ProcessSP process_sp;
// Make sure we stop at the entry point
launch_info.GetFlags ().Set (eLaunchFlagDebug);
@@ -1051,12 +1124,16 @@ Platform::DebugProcess (ProcessLaunchInfo &launch_info,
error = LaunchProcess (launch_info);
if (error.Success())
{
+ if (log)
+ log->Printf ("Platform::%s LaunchProcess() call succeeded (pid=%" PRIu64 ")", __FUNCTION__, launch_info.GetProcessID ());
if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
{
ProcessAttachInfo attach_info (launch_info);
- process_sp = Attach (attach_info, debugger, target, listener, error);
+ process_sp = Attach (attach_info, debugger, target, error);
if (process_sp)
{
+ if (log)
+ log->Printf ("Platform::%s Attach() succeeded, Process plugin: %s", __FUNCTION__, process_sp->GetPluginName ().AsCString ());
launch_info.SetHijackListener(attach_info.GetHijackListener());
// Since we attached to the process, it will think it needs to detach
@@ -1075,8 +1152,24 @@ Platform::DebugProcess (ProcessLaunchInfo &launch_info,
process_sp->SetSTDIOFileDescriptor(pty_fd);
}
}
+ else
+ {
+ if (log)
+ log->Printf ("Platform::%s Attach() failed: %s", __FUNCTION__, error.AsCString ());
+ }
}
+ else
+ {
+ if (log)
+ log->Printf ("Platform::%s LaunchProcess() returned launch_info with invalid process id", __FUNCTION__);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Platform::%s LaunchProcess() failed: %s", __FUNCTION__, error.AsCString ());
}
+
return process_sp;
}
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index a1049787d821..106678da2684 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -16,22 +16,25 @@
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Event.h"
-#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Symbol/Symbol.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Expression/ClangUserExpression.h"
-#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Pipe.h"
#include "lldb/Host/Terminal.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/JITLoader.h"
+#include "lldb/Target/MemoryHistory.h"
#include "lldb/Target/OperatingSystem.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/CPPLanguageRuntime.h"
@@ -45,6 +48,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanBase.h"
+#include "lldb/Target/InstrumentationRuntime.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
using namespace lldb;
@@ -108,6 +112,7 @@ g_properties[] =
{ "python-os-plugin-path", OptionValue::eTypeFileSpec, false, true, NULL, NULL, "A path to a python OS plug-in module file that contains a OperatingSystemPlugIn class." },
{ "stop-on-sharedlibrary-events" , OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, stop when a shared library is loaded or unloaded." },
{ "detach-keeps-stopped" , OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, detach will attempt to keep the process stopped." },
+ { "memory-cache-line-size" , OptionValue::eTypeUInt64, false, 512, NULL, NULL, "The memory cache line size" },
{ NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
};
@@ -118,14 +123,17 @@ enum {
ePropertyUnwindOnErrorInExpressions,
ePropertyPythonOSPluginPath,
ePropertyStopOnSharedLibraryEvents,
- ePropertyDetachKeepsStopped
+ ePropertyDetachKeepsStopped,
+ ePropertyMemCacheLineSize
};
-ProcessProperties::ProcessProperties (bool is_global) :
- Properties ()
+ProcessProperties::ProcessProperties (lldb_private::Process *process) :
+ Properties (),
+ m_process (process) // Can be NULL for global ProcessProperties
{
- if (is_global)
+ if (process == NULL)
{
+ // Global process properties, set them up one time
m_collection_sp.reset (new ProcessOptionValueProperties(ConstString("process")));
m_collection_sp->Initialize(g_properties);
m_collection_sp->AppendProperty(ConstString("thread"),
@@ -134,13 +142,24 @@ ProcessProperties::ProcessProperties (bool is_global) :
Thread::GetGlobalProperties()->GetValueProperties());
}
else
+ {
m_collection_sp.reset (new ProcessOptionValueProperties(Process::GetGlobalProperties().get()));
+ m_collection_sp->SetValueChangedCallback(ePropertyPythonOSPluginPath, ProcessProperties::OptionValueChangedCallback, this);
+ }
}
ProcessProperties::~ProcessProperties()
{
}
+void
+ProcessProperties::OptionValueChangedCallback (void *baton, OptionValue *option_value)
+{
+ ProcessProperties *properties = (ProcessProperties *)baton;
+ if (properties->m_process)
+ properties->m_process->LoadOperatingSystemPlugin(true);
+}
+
bool
ProcessProperties::GetDisableMemoryCache() const
{
@@ -148,6 +167,13 @@ ProcessProperties::GetDisableMemoryCache() const
return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
}
+uint64_t
+ProcessProperties::GetMemoryCacheLineSize() const
+{
+ const uint32_t idx = ePropertyMemCacheLineSize;
+ return m_collection_sp->GetPropertyAtIndexAsUInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
Args
ProcessProperties::GetExtraStartupCommands () const
{
@@ -467,9 +493,9 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
case 'c':
if (option_arg && option_arg[0])
- launch_info.SetShell (option_arg);
+ launch_info.SetShell (FileSpec(option_arg, false));
else
- launch_info.SetShell (LLDB_DEFAULT_SHELL);
+ launch_info.SetShell (HostInfo::GetDefaultShell());
break;
case 'v':
@@ -660,7 +686,7 @@ Process::Process(Target &target, Listener &listener) :
}
Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_signals_sp) :
- ProcessProperties (false),
+ ProcessProperties (this),
UserID (LLDB_INVALID_PROCESS_ID),
Broadcaster (&(target.GetDebugger()), "lldb.process"),
m_target (target),
@@ -670,13 +696,13 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
m_private_state_control_broadcaster (NULL, "lldb.process.internal_state_control_broadcaster"),
m_private_state_listener ("lldb.process.internal_state_listener"),
m_private_state_control_wait(),
- m_private_state_thread (LLDB_INVALID_HOST_THREAD),
m_mod_id (),
m_process_unique_id(0),
m_thread_index_id (0),
m_thread_id_to_index_id_map (),
m_exit_status (-1),
m_exit_string (),
+ m_exit_status_mutex(),
m_thread_mutex (Mutex::eMutexTypeRecursive),
m_thread_list_real (this),
m_thread_list (this),
@@ -706,6 +732,7 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
m_public_run_lock (),
m_private_run_lock (),
m_currently_handling_event(false),
+ m_stop_info_override_callback (NULL),
m_finalize_called(false),
m_clear_thread_plans_on_stop (false),
m_force_next_event_delivery(false),
@@ -760,6 +787,11 @@ Process::~Process()
if (log)
log->Printf ("%p Process::~Process()", static_cast<void*>(this));
StopPrivateStateThread();
+
+ // ThreadList::Clear() will try to acquire this process's mutex, so
+ // explicitly clear the thread list here to ensure that the mutex
+ // is not destroyed before the thread list.
+ m_thread_list.Clear();
}
const ProcessPropertiesSP &
@@ -767,7 +799,7 @@ Process::GetGlobalProperties()
{
static ProcessPropertiesSP g_settings_sp;
if (!g_settings_sp)
- g_settings_sp.reset (new ProcessProperties (true));
+ g_settings_sp.reset (new ProcessProperties (NULL));
return g_settings_sp;
}
@@ -826,7 +858,9 @@ Process::Finalize()
m_memory_cache.Clear();
m_allocated_memory_cache.Clear();
m_language_runtimes.clear();
+ m_instrumentation_runtimes.clear();
m_next_event_action_ap.reset();
+ m_stop_info_override_callback = NULL;
//#ifdef LLDB_CONFIGURATION_DEBUG
// StreamFile s(stdout, false);
// EventSP event_sp;
@@ -924,7 +958,7 @@ Process::SyncIOHandler (uint64_t timeout_msec)
log->Printf ("Process::%s pid %" PRIu64 ": SUCCESS", __FUNCTION__, GetID ());
}
- // reset sync one-shot so it will be ready for next time
+ // reset sync one-shot so it will be ready for next launch
m_iohandler_sync.SetValue(false, eBroadcastNever);
}
@@ -932,7 +966,11 @@ Process::SyncIOHandler (uint64_t timeout_msec)
}
StateType
-Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr, bool wait_always, Listener *hijack_listener)
+Process::WaitForProcessToStop (const TimeValue *timeout,
+ EventSP *event_sp_ptr,
+ bool wait_always,
+ Listener *hijack_listener,
+ Stream *stream)
{
// We can't just wait for a "stopped" event, because the stopped event may have restarted the target.
// We have to actually check each event, and in the case of a stopped event check the restarted flag
@@ -966,6 +1004,9 @@ Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp
if (event_sp_ptr && event_sp)
*event_sp_ptr = event_sp;
+ bool pop_process_io_handler = hijack_listener != NULL;
+ Process::HandleProcessStateChangedEvent (event_sp, stream, pop_process_io_handler);
+
switch (state)
{
case eStateCrashed:
@@ -995,6 +1036,195 @@ Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp
return state;
}
+bool
+Process::HandleProcessStateChangedEvent (const EventSP &event_sp,
+ Stream *stream,
+ bool &pop_process_io_handler)
+{
+ const bool handle_pop = pop_process_io_handler == true;
+
+ pop_process_io_handler = false;
+ ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
+
+ if (!process_sp)
+ return false;
+
+ StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
+ if (event_state == eStateInvalid)
+ return false;
+
+ switch (event_state)
+ {
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateStepping:
+ case eStateDetached:
+ {
+ if (stream)
+ stream->Printf ("Process %" PRIu64 " %s\n",
+ process_sp->GetID(),
+ StateAsCString (event_state));
+
+ if (event_state == eStateDetached)
+ pop_process_io_handler = true;
+ }
+ break;
+
+ case eStateConnected:
+ case eStateRunning:
+ // Don't be chatty when we run...
+ break;
+
+ case eStateExited:
+ if (stream)
+ process_sp->GetStatus(*stream);
+ pop_process_io_handler = true;
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ // Make sure the program hasn't been auto-restarted:
+ if (Process::ProcessEventData::GetRestartedFromEvent (event_sp.get()))
+ {
+ if (stream)
+ {
+ size_t num_reasons = Process::ProcessEventData::GetNumRestartedReasons(event_sp.get());
+ if (num_reasons > 0)
+ {
+ // FIXME: Do we want to report this, or would that just be annoyingly chatty?
+ if (num_reasons == 1)
+ {
+ const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), 0);
+ stream->Printf ("Process %" PRIu64 " stopped and restarted: %s\n",
+ process_sp->GetID(),
+ reason ? reason : "<UNKNOWN REASON>");
+ }
+ else
+ {
+ stream->Printf ("Process %" PRIu64 " stopped and restarted, reasons:\n",
+ process_sp->GetID());
+
+
+ for (size_t i = 0; i < num_reasons; i++)
+ {
+ const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), i);
+ stream->Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>");
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Lock the thread list so it doesn't change on us, this is the scope for the locker:
+ {
+ ThreadList &thread_list = process_sp->GetThreadList();
+ Mutex::Locker locker (thread_list.GetMutex());
+
+ ThreadSP curr_thread (thread_list.GetSelectedThread());
+ ThreadSP thread;
+ StopReason curr_thread_stop_reason = eStopReasonInvalid;
+ if (curr_thread)
+ curr_thread_stop_reason = curr_thread->GetStopReason();
+ if (!curr_thread ||
+ !curr_thread->IsValid() ||
+ curr_thread_stop_reason == eStopReasonInvalid ||
+ curr_thread_stop_reason == eStopReasonNone)
+ {
+ // Prefer a thread that has just completed its plan over another thread as current thread.
+ ThreadSP plan_thread;
+ ThreadSP other_thread;
+ const size_t num_threads = thread_list.GetSize();
+ size_t i;
+ for (i = 0; i < num_threads; ++i)
+ {
+ thread = thread_list.GetThreadAtIndex(i);
+ StopReason thread_stop_reason = thread->GetStopReason();
+ switch (thread_stop_reason)
+ {
+ case eStopReasonInvalid:
+ case eStopReasonNone:
+ break;
+
+ case eStopReasonTrace:
+ case eStopReasonBreakpoint:
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ case eStopReasonExec:
+ case eStopReasonThreadExiting:
+ case eStopReasonInstrumentation:
+ if (!other_thread)
+ other_thread = thread;
+ break;
+ case eStopReasonPlanComplete:
+ if (!plan_thread)
+ plan_thread = thread;
+ break;
+ }
+ }
+ if (plan_thread)
+ thread_list.SetSelectedThreadByID (plan_thread->GetID());
+ else if (other_thread)
+ thread_list.SetSelectedThreadByID (other_thread->GetID());
+ else
+ {
+ if (curr_thread && curr_thread->IsValid())
+ thread = curr_thread;
+ else
+ thread = thread_list.GetThreadAtIndex(0);
+
+ if (thread)
+ thread_list.SetSelectedThreadByID (thread->GetID());
+ }
+ }
+ }
+ // Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code,
+ // e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to
+ // have a hard time restarting the process.
+ if (stream)
+ {
+ Debugger &debugger = process_sp->GetTarget().GetDebugger();
+ if (debugger.GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget())
+ {
+ const bool only_threads_with_stop_reason = true;
+ const uint32_t start_frame = 0;
+ const uint32_t num_frames = 1;
+ const uint32_t num_frames_with_source = 1;
+ process_sp->GetStatus(*stream);
+ process_sp->GetThreadStatus (*stream,
+ only_threads_with_stop_reason,
+ start_frame,
+ num_frames,
+ num_frames_with_source);
+ }
+ else
+ {
+ uint32_t target_idx = debugger.GetTargetList().GetIndexOfTarget(process_sp->GetTarget().shared_from_this());
+ if (target_idx != UINT32_MAX)
+ stream->Printf ("Target %d: (", target_idx);
+ else
+ stream->Printf ("Target <unknown index>: (");
+ process_sp->GetTarget().Dump (stream, eDescriptionLevelBrief);
+ stream->Printf (") stopped.\n");
+ }
+ }
+
+ // Pop the process IO handler
+ pop_process_io_handler = true;
+ }
+ break;
+ }
+
+ if (handle_pop && pop_process_io_handler)
+ process_sp->PopProcessIOHandler();
+
+ return true;
+}
+
StateType
Process::WaitForState
@@ -1170,6 +1400,8 @@ Process::IsRunning () const
int
Process::GetExitStatus ()
{
+ Mutex::Locker locker (m_exit_status_mutex);
+
if (m_public_state.GetValue() == eStateExited)
return m_exit_status;
return -1;
@@ -1179,6 +1411,8 @@ Process::GetExitStatus ()
const char *
Process::GetExitDescription ()
{
+ Mutex::Locker locker (m_exit_status_mutex);
+
if (m_public_state.GetValue() == eStateExited && !m_exit_string.empty())
return m_exit_string.c_str();
return NULL;
@@ -1203,11 +1437,16 @@ Process::SetExitStatus (int status, const char *cstr)
return false;
}
- m_exit_status = status;
- if (cstr)
- m_exit_string = cstr;
- else
- m_exit_string.clear();
+ // 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();
+ }
DidExit ();
@@ -1392,6 +1631,17 @@ Process::GetState()
return m_public_state.GetValue ();
}
+bool
+Process::StateChangedIsExternallyHijacked()
+{
+ if (IsHijackedForEvent(eBroadcastBitStateChanged))
+ {
+ if (strcmp(m_hijacking_listeners.back()->GetName(), "lldb.Process.ResumeSynchronous.hijack"))
+ return true;
+ }
+ return false;
+}
+
void
Process::SetPublicState (StateType new_state, bool restarted)
{
@@ -1404,7 +1654,7 @@ Process::SetPublicState (StateType new_state, bool restarted)
// On the transition from Run to Stopped, we unlock the writer end of the
// run lock. The lock gets locked in Resume, which is the public API
// to tell the program to run.
- if (!IsHijackedForEvent(eBroadcastBitStateChanged))
+ if (!StateChangedIsExternallyHijacked())
{
if (new_state == eStateDetached)
{
@@ -1445,6 +1695,36 @@ Process::Resume ()
return PrivateResume();
}
+Error
+Process::ResumeSynchronous (Stream *stream)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::ResumeSynchronous -- locking run lock");
+ if (!m_public_run_lock.TrySetRunning())
+ {
+ Error error("Resume request failed - process still running.");
+ if (log)
+ log->Printf ("Process::Resume: -- TrySetRunning failed, not resuming.");
+ return error;
+ }
+
+ ListenerSP listener_sp (new Listener("lldb.Process.ResumeSynchronous.hijack"));
+ HijackProcessEvents(listener_sp.get());
+
+ Error error = PrivateResume();
+
+ StateType state = WaitForProcessToStop (NULL, NULL, true, listener_sp.get(), stream);
+
+ // 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;
+}
+
StateType
Process::GetPrivateState ()
{
@@ -1617,12 +1897,17 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)
{
if (error_str_sp->IsCStringContainer(true))
{
- StreamString s;
- size_t num_chars = error_str_sp->ReadPointedString (s, error);
+ DataBufferSP buffer_sp(new DataBufferHeap(10240,0));
+ size_t num_chars = error_str_sp->ReadPointedString (buffer_sp, error, 10240);
if (error.Success() && num_chars > 0)
{
error.Clear();
- error.SetErrorStringWithFormat("dlopen error: %s", s.GetData());
+ error.SetErrorStringWithFormat("dlopen error: %s", buffer_sp->GetBytes());
+ }
+ else
+ {
+ error.Clear();
+ error.SetErrorStringWithFormat("dlopen failed for unknown reasons.");
}
}
}
@@ -2507,10 +2792,10 @@ Process::WriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
});
if (bytes_written < size)
- bytes_written += WriteMemoryPrivate (addr + bytes_written,
- ubuf + bytes_written,
- size - bytes_written,
- error);
+ WriteMemoryPrivate (addr + bytes_written,
+ ubuf + bytes_written,
+ size - bytes_written,
+ error);
}
}
else
@@ -2722,6 +3007,16 @@ Process::WaitForProcessStopPrivate (const TimeValue *timeout, EventSP &event_sp)
return state;
}
+void
+Process::LoadOperatingSystemPlugin(bool flush)
+{
+ if (flush)
+ m_thread_list.Clear();
+ m_os_ap.reset (OperatingSystem::FindPlugin (this, NULL));
+ if (flush)
+ Flush();
+}
+
Error
Process::Launch (ProcessLaunchInfo &launch_info)
{
@@ -2732,6 +3027,7 @@ Process::Launch (ProcessLaunchInfo &launch_info)
m_system_runtime_ap.reset();
m_os_ap.reset();
m_process_input_reader.reset();
+ m_stop_info_override_callback = NULL;
Module *exe_module = m_target.GetExecutableModulePointer();
if (exe_module)
@@ -2811,15 +3107,20 @@ Process::Launch (ProcessLaunchInfo &launch_info)
if (system_runtime)
system_runtime->DidLaunch();
- m_os_ap.reset (OperatingSystem::FindPlugin (this, NULL));
- // This delays passing the stopped event to listeners till DidLaunch gets
- // a chance to complete...
- HandlePrivateEvent (event_sp);
+ LoadOperatingSystemPlugin(false);
+
+ // Note, the stop event was consumed above, but not handled. This was done
+ // to give DidLaunch a chance to run. The target is either stopped or crashed.
+ // Directly set the state. This is done to prevent a stop message with a bunch
+ // of spurious output on thread status, as well as not pop a ProcessIOHandler.
+ SetPublicState(state, false);
if (PrivateStateThreadIsValid ())
ResumePrivateStateThread ();
else
StartPrivateStateThread ();
+
+ m_stop_info_override_callback = GetTarget().GetArchitecture().GetStopInfoOverrideCallback();
}
else if (state == eStateExited)
{
@@ -2979,6 +3280,15 @@ Process::AttachCompletionHandler::GetExitString ()
return m_exit_string.c_str();
}
+Listener &
+ProcessAttachInfo::GetListenerForProcess (Debugger &debugger)
+{
+ if (m_listener_sp)
+ return *m_listener_sp;
+ else
+ return debugger.GetListener();
+}
+
Error
Process::Attach (ProcessAttachInfo &attach_info)
{
@@ -2988,6 +3298,7 @@ Process::Attach (ProcessAttachInfo &attach_info)
m_jit_loaders_ap.reset();
m_system_runtime_ap.reset();
m_os_ap.reset();
+ m_stop_info_override_callback = NULL;
lldb::pid_t attach_pid = attach_info.GetProcessID();
Error error;
@@ -3115,14 +3426,13 @@ Process::Attach (ProcessAttachInfo &attach_info)
else
{
if (GetID() != LLDB_INVALID_PROCESS_ID)
- {
SetID (LLDB_INVALID_PROCESS_ID);
- const char *error_string = error.AsCString();
- if (error_string == NULL)
- error_string = "attach failed";
- SetExitStatus(-1, error_string);
- }
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "attach failed";
+
+ SetExitStatus(-1, error_string);
}
}
}
@@ -3246,6 +3556,8 @@ Process::CompleteAttach ()
exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>");
}
}
+
+ m_stop_info_override_callback = process_arch.GetStopInfoOverrideCallback();
}
Error
@@ -3823,26 +4135,25 @@ Process::StartPrivateStateThread (bool force)
// events make it to clients (into the DCProcess event queue).
char thread_name[1024];
- if (Host::MAX_THREAD_NAME_LENGTH <= 16)
+ if (HostInfo::GetMaxThreadNameLength() <= 30)
{
- // On platforms with abbreviated thread name lengths, choose thread names that fit within the limit.
- if (already_running)
- snprintf(thread_name, sizeof(thread_name), "intern-state-OV");
- else
- snprintf(thread_name, sizeof(thread_name), "intern-state");
+ // On platforms with abbreviated thread name lengths, choose thread names that fit within the limit.
+ if (already_running)
+ snprintf(thread_name, sizeof(thread_name), "intern-state-OV");
+ else
+ snprintf(thread_name, sizeof(thread_name), "intern-state");
}
else
{
if (already_running)
- snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", GetID());
+ snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", GetID());
else
- snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID());
+ snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID());
}
// Create the private state thread, and start it running.
- m_private_state_thread = Host::ThreadCreate (thread_name, Process::PrivateStateThread, this, NULL);
- bool success = IS_VALID_LLDB_HOST_THREAD(m_private_state_thread);
- if (success)
+ m_private_state_thread = ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread, this, NULL);
+ if (m_private_state_thread.IsJoinable())
{
ResumePrivateStateThread();
return true;
@@ -3891,8 +4202,8 @@ Process::ControlPrivateStateThread (uint32_t signal)
// Signal the private state thread. First we should copy this is case the
// thread starts exiting since the private state thread will NULL this out
// when it exits
- const lldb::thread_t private_state_thread = m_private_state_thread;
- if (IS_VALID_LLDB_HOST_THREAD(private_state_thread))
+ HostThread private_state_thread(m_private_state_thread);
+ if (private_state_thread.IsJoinable())
{
TimeValue timeout_time;
bool timed_out;
@@ -3910,8 +4221,7 @@ Process::ControlPrivateStateThread (uint32_t signal)
{
if (timed_out)
{
- Error error;
- Host::ThreadCancel (private_state_thread, &error);
+ Error error = private_state_thread.Cancel();
if (log)
log->Printf ("Timed out responding to the control event, cancel got error: \"%s\".", error.AsCString());
}
@@ -3922,8 +4232,8 @@ Process::ControlPrivateStateThread (uint32_t signal)
}
thread_result_t result = NULL;
- Host::ThreadJoin (private_state_thread, &result, NULL);
- m_private_state_thread = LLDB_INVALID_HOST_THREAD;
+ private_state_thread.Join(&result);
+ m_private_state_thread.Reset();
}
}
else
@@ -4005,7 +4315,8 @@ 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...
- if (!GetTarget().GetDebugger().IsForwardingEvents())
+ // Or don't push it if we are launching since it will come up stopped.
+ if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching)
PushProcessIOHandler ();
m_iohandler_sync.SetValue(true, eBroadcastAlways);
}
@@ -4167,7 +4478,7 @@ Process::RunPrivateStateThread ()
m_public_run_lock.SetStopped();
m_private_state_control_wait.SetValue (true, eBroadcastAlways);
- m_private_state_thread = LLDB_INVALID_HOST_THREAD;
+ m_private_state_thread.Reset();
return NULL;
}
@@ -4621,7 +4932,7 @@ class IOHandlerProcessSTDIO :
public:
IOHandlerProcessSTDIO (Process *process,
int write_fd) :
- IOHandler(process->GetTarget().GetDebugger()),
+ IOHandler(process->GetTarget().GetDebugger(), IOHandler::Type::ProcessIO),
m_process (process),
m_read_file (),
m_write_file (write_fd, false),
@@ -4639,9 +4950,10 @@ public:
bool
OpenPipes ()
{
- if (m_pipe.IsValid())
+ if (m_pipe.CanRead() && m_pipe.CanWrite())
return true;
- return m_pipe.Open();
+ Error result = m_pipe.CreateNew(false);
+ return result.Success();
}
void
@@ -4702,8 +5014,10 @@ public:
}
if (FD_ISSET (pipe_read_fd, &read_fdset))
{
+ size_t bytes_read;
// Consume the interrupt byte
- if (m_pipe.Read (&ch, 1) == 1)
+ Error error = m_pipe.Read(&ch, 1, bytes_read);
+ if (error.Success())
{
switch (ch)
{
@@ -4751,7 +5065,8 @@ public:
Cancel ()
{
char ch = 'q'; // Send 'q' for quit
- m_pipe.Write (&ch, 1);
+ size_t bytes_written = 0;
+ m_pipe.Write(&ch, 1, bytes_written);
}
virtual bool
@@ -4765,7 +5080,9 @@ public:
if (m_active)
{
char ch = 'i'; // Send 'i' for interrupt
- return m_pipe.Write (&ch, 1) == 1;
+ size_t bytes_written = 0;
+ Error result = m_pipe.Write(&ch, 1, bytes_written);
+ return result.Success();
}
else
{
@@ -4944,12 +5261,12 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
selected_tid = LLDB_INVALID_THREAD_ID;
}
- lldb::thread_t backup_private_state_thread = LLDB_INVALID_HOST_THREAD;
- lldb::StateType old_state;
+ HostThread backup_private_state_thread;
+ lldb::StateType old_state = eStateInvalid;
lldb::ThreadPlanSP stopper_base_plan_sp;
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
- if (Host::GetCurrentThread() == m_private_state_thread)
+ if (m_private_state_thread.EqualsThread(Host::GetCurrentThread()))
{
// Yikes, we are running on the private state thread! So we can't wait for public events on this thread, since
// we are the thread that is generating public events.
@@ -5554,7 +5871,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
} // END WAIT LOOP
// If we had to start up a temporary private state thread to run this thread plan, shut it down now.
- if (IS_VALID_LLDB_HOST_THREAD(backup_private_state_thread))
+ if (backup_private_state_thread.IsJoinable())
{
StopPrivateStateThread();
Error error;
@@ -5563,8 +5880,8 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
thread->DiscardThreadPlansUpToPlan(stopper_base_plan_sp);
}
- m_public_state.SetValueNoLock(old_state);
-
+ if (old_state != eStateInvalid)
+ m_public_state.SetValueNoLock(old_state);
}
// Restore the thread state if we are going to discard the plan execution. There are three cases where this
@@ -5848,21 +6165,21 @@ Process::GetThreadStatus (Stream &strm,
// ID's, and look them up one by one:
uint32_t num_threads;
- std::vector<uint32_t> thread_index_array;
+ std::vector<lldb::tid_t> thread_id_array;
//Scope for thread list locker;
{
Mutex::Locker locker (GetThreadList().GetMutex());
ThreadList &curr_thread_list = GetThreadList();
num_threads = curr_thread_list.GetSize();
uint32_t idx;
- thread_index_array.resize(num_threads);
+ thread_id_array.resize(num_threads);
for (idx = 0; idx < num_threads; ++idx)
- thread_index_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID();
+ thread_id_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID();
}
for (uint32_t i = 0; i < num_threads; i++)
{
- ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_index_array[i]));
+ ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_id_array[i]));
if (thread_sp)
{
if (only_threads_with_stop_reason)
@@ -5915,7 +6232,8 @@ Process::RunPreResumeActions ()
struct PreResumeCallbackAndBaton action = m_pre_resume_actions.back();
m_pre_resume_actions.pop_back();
bool this_result = action.callback (action.baton);
- if (result == true) result = this_result;
+ if (result == true)
+ result = this_result;
}
return result;
}
@@ -5955,8 +6273,10 @@ Process::DidExec ()
m_image_tokens.clear();
m_allocated_memory_cache.Clear();
m_language_runtimes.clear();
+ m_instrumentation_runtimes.clear();
m_thread_list.DiscardThreadPlans();
m_memory_cache.Clear(true);
+ m_stop_info_override_callback = NULL;
DoDidExec();
CompleteAttach ();
// Flush the process (threads and all stack frames) after running CompleteAttach()
@@ -6005,11 +6325,51 @@ Process::ResolveIndirectFunction(const Address *address, Error &error)
void
Process::ModulesDidLoad (ModuleList &module_list)
{
- SystemRuntime *sys_runtime = GetSystemRuntime();
- if (sys_runtime)
- {
- sys_runtime->ModulesDidLoad (module_list);
- }
+ SystemRuntime *sys_runtime = GetSystemRuntime();
+ if (sys_runtime)
+ {
+ sys_runtime->ModulesDidLoad (module_list);
+ }
+
+ GetJITLoaders().ModulesDidLoad (module_list);
+
+ // Give runtimes a chance to be created.
+ InstrumentationRuntime::ModulesDidLoad(module_list, this, m_instrumentation_runtimes);
+
+ // Tell runtimes about new modules.
+ for (auto pos = m_instrumentation_runtimes.begin(); pos != m_instrumentation_runtimes.end(); ++pos)
+ {
+ InstrumentationRuntimeSP runtime = pos->second;
+ runtime->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()) {
+ return threads;
+ }
+
+ threads.reset(new ThreadCollection(memory_history->GetHistoryThreads(addr)));
+
+ return threads;
+}
- GetJITLoaders().ModulesDidLoad (module_list);
+InstrumentationRuntimeSP
+Process::GetInstrumentationRuntime(lldb::InstrumentationRuntimeType type)
+{
+ InstrumentationRuntimeCollection::iterator pos;
+ pos = m_instrumentation_runtimes.find (type);
+ if (pos == m_instrumentation_runtimes.end())
+ {
+ return InstrumentationRuntimeSP();
+ }
+ else
+ return (*pos).second;
}
diff --git a/source/Target/ProcessLaunchInfo.cpp b/source/Target/ProcessLaunchInfo.cpp
index 830f1470ed98..451c42d18bfa 100644
--- a/source/Target/ProcessLaunchInfo.cpp
+++ b/source/Target/ProcessLaunchInfo.cpp
@@ -9,10 +9,8 @@
#include "lldb/Host/Config.h"
-#ifndef LLDB_DISABLE_POSIX
-#include <spawn.h>
-#endif
-
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/FileAction.h"
#include "lldb/Target/Target.h"
@@ -28,32 +26,32 @@ ProcessLaunchInfo::ProcessLaunchInfo () :
ProcessInfo(),
m_working_dir (),
m_plugin_name (),
- m_shell (),
m_flags (0),
m_file_actions (),
- m_pty (),
+ m_pty (new lldb_utility::PseudoTerminal),
m_resume_count (0),
m_monitor_callback (NULL),
m_monitor_callback_baton (NULL),
m_monitor_signals (false),
+ m_listener_sp (),
m_hijack_listener_sp ()
{
}
ProcessLaunchInfo::ProcessLaunchInfo(const char *stdin_path, const char *stdout_path, const char *stderr_path,
- const char *working_directory, uint32_t launch_flags)
- : ProcessInfo()
- , m_working_dir()
- , m_plugin_name()
- , m_shell()
- , m_flags(launch_flags)
- , m_file_actions()
- , m_pty()
- , m_resume_count(0)
- , m_monitor_callback(NULL)
- , m_monitor_callback_baton(NULL)
- , m_monitor_signals(false)
- , m_hijack_listener_sp()
+ const char *working_directory, uint32_t launch_flags) :
+ ProcessInfo(),
+ m_working_dir(),
+ m_plugin_name(),
+ m_flags(launch_flags),
+ m_file_actions(),
+ m_pty(new lldb_utility::PseudoTerminal),
+ m_resume_count(0),
+ m_monitor_callback(NULL),
+ m_monitor_callback_baton(NULL),
+ m_monitor_signals(false),
+ m_listener_sp (),
+ m_hijack_listener_sp()
{
if (stdin_path)
{
@@ -184,27 +182,23 @@ ProcessLaunchInfo::SetProcessPluginName (const char *plugin)
m_plugin_name.clear();
}
-const char *
+const FileSpec &
ProcessLaunchInfo::GetShell () const
{
- if (m_shell.empty())
- return NULL;
- return m_shell.c_str();
+ return m_shell;
}
void
-ProcessLaunchInfo::SetShell (const char * path)
+ProcessLaunchInfo::SetShell (const FileSpec &shell)
{
- if (path && path[0])
+ m_shell = shell;
+ if (m_shell)
{
- m_shell.assign (path);
+ m_shell.ResolveExecutableLocation();
m_flags.Set (lldb::eLaunchFlagLaunchInShell);
}
else
- {
- m_shell.clear();
m_flags.Clear (lldb::eLaunchFlagLaunchInShell);
- }
}
void
@@ -223,10 +217,11 @@ ProcessLaunchInfo::Clear ()
ProcessInfo::Clear();
m_working_dir.clear();
m_plugin_name.clear();
- m_shell.clear();
+ m_shell.Clear();
m_flags.Clear();
m_file_actions.clear();
m_resume_count = 0;
+ m_listener_sp.reset();
m_hijack_listener_sp.reset();
}
@@ -266,13 +261,23 @@ ProcessLaunchInfo::SetDetachOnError (bool enable)
void
ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
// If nothing for stdin or stdout or stderr was specified, then check the process for any default
// settings that were set with "settings set"
- if (GetFileActionForFD(STDIN_FILENO) == NULL || GetFileActionForFD(STDOUT_FILENO) == NULL ||
+ if (GetFileActionForFD(STDIN_FILENO) == NULL ||
+ GetFileActionForFD(STDOUT_FILENO) == NULL ||
GetFileActionForFD(STDERR_FILENO) == NULL)
{
+ if (log)
+ log->Printf ("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr was not set, evaluating default handling",
+ __FUNCTION__);
+
if (m_flags.Test(eLaunchFlagDisableSTDIO))
{
+ if (log)
+ log->Printf ("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding suppression action for stdin, stdout and stderr",
+ __FUNCTION__);
AppendSuppressFileAction (STDIN_FILENO , true, false);
AppendSuppressFileAction (STDOUT_FILENO, false, true);
AppendSuppressFileAction (STDERR_FILENO, false, true);
@@ -288,34 +293,79 @@ ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
FileSpec err_path;
if (target)
{
- in_path = target->GetStandardInputPath();
- out_path = target->GetStandardOutputPath();
- err_path = target->GetStandardErrorPath();
+ // 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();
+ if (GetFileActionForFD(STDOUT_FILENO) == NULL)
+ out_path = target->GetStandardOutputPath();
+ if (GetFileActionForFD(STDERR_FILENO) == NULL)
+ err_path = 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>");
+
char path[PATH_MAX];
if (in_path && in_path.GetPath(path, sizeof(path)))
+ {
AppendOpenFileAction(STDIN_FILENO, path, true, false);
+ if (log)
+ log->Printf ("ProcessLaunchInfo::%s appended stdin open file action for %s",
+ __FUNCTION__,
+ in_path.GetPath().c_str ());
+ }
if (out_path && out_path.GetPath(path, sizeof(path)))
+ {
AppendOpenFileAction(STDOUT_FILENO, path, false, true);
+ if (log)
+ log->Printf ("ProcessLaunchInfo::%s appended stdout open file action for %s",
+ __FUNCTION__,
+ out_path.GetPath().c_str ());
+ }
if (err_path && err_path.GetPath(path, sizeof(path)))
+ {
+ 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);
+ }
+
+ if (default_to_use_pty && (!in_path || !out_path || !err_path))
+ {
+ 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",
+ __FUNCTION__);
- if (default_to_use_pty && (!in_path || !out_path || !err_path)) {
- if (m_pty.OpenFirstAvailableMaster(O_RDWR| O_NOCTTY, NULL, 0)) {
- const char *slave_path = m_pty.GetSlaveName(NULL, 0);
+ if (m_pty->OpenFirstAvailableMaster(O_RDWR| O_NOCTTY, NULL, 0))
+ {
+ const char *slave_path = m_pty->GetSlaveName(NULL, 0);
- if (!in_path) {
+ // 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)
+ {
AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
}
- if (!out_path) {
+ // 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)
+ {
AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
}
- if (!err_path) {
+ // 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)
+ {
AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
}
}
@@ -336,42 +386,30 @@ ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
if (GetFlags().Test (eLaunchFlagLaunchInShell))
{
- const char *shell_executable = GetShell();
- if (shell_executable)
+ if (m_shell)
{
- char shell_resolved_path[PATH_MAX];
-
- if (localhost)
- {
- FileSpec shell_filespec (shell_executable, true);
-
- if (!shell_filespec.Exists())
- {
- // Resolve the path in case we just got "bash", "sh" or "tcsh"
- if (!shell_filespec.ResolveExecutableLocation ())
- {
- error.SetErrorStringWithFormat("invalid shell path '%s'", shell_executable);
- return false;
- }
- }
- shell_filespec.GetPath (shell_resolved_path, sizeof(shell_resolved_path));
- shell_executable = shell_resolved_path;
- }
+ std::string shell_executable = m_shell.GetPath();
const char **argv = GetArguments().GetConstArgumentVector ();
if (argv == NULL || argv[0] == NULL)
return false;
Args shell_arguments;
std::string safe_arg;
- shell_arguments.AppendArgument (shell_executable);
- shell_arguments.AppendArgument ("-c");
+ shell_arguments.AppendArgument (shell_executable.c_str());
+ const llvm::Triple &triple = GetArchitecture().GetTriple();
+ if (triple.getOS() == llvm::Triple::Win32 && !triple.isWindowsCygwinEnvironment())
+ shell_arguments.AppendArgument("/C");
+ else
+ shell_arguments.AppendArgument("-c");
+
StreamString shell_command;
if (will_debug)
{
// Add a modified PATH environment variable in case argv[0]
- // is a relative path
+ // is a relative path.
const char *argv0 = argv[0];
- if (argv0 && (argv0[0] != '/' && argv0[0] != '~'))
+ FileSpec arg_spec(argv0, false);
+ if (arg_spec.IsRelativeToCurrentWorkingDirectory())
{
// 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")
@@ -402,7 +440,8 @@ ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
shell_command.PutCString(new_path.c_str());
}
- shell_command.PutCString ("exec");
+ if (triple.getOS() != llvm::Triple::Win32 || triple.isWindowsCygwinEnvironment())
+ shell_command.PutCString("exec");
// Only Apple supports /usr/bin/arch being able to specify the architecture
if (GetArchitecture().IsValid() && // Valid architecture
@@ -442,7 +481,7 @@ ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
}
}
shell_arguments.AppendArgument (shell_command.GetString().c_str());
- m_executable.SetFile(shell_executable, false);
+ m_executable = m_shell;
m_arguments = shell_arguments;
return true;
}
@@ -457,3 +496,12 @@ ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
}
return false;
}
+
+Listener &
+ProcessLaunchInfo::GetListenerForProcess (Debugger &debugger)
+{
+ if (m_listener_sp)
+ return *m_listener_sp;
+ else
+ return debugger.GetListener();
+}
diff --git a/source/Target/StackFrame.cpp b/source/Target/StackFrame.cpp
index e497b176ccfe..c46db4cfadf9 100644
--- a/source/Target/StackFrame.cpp
+++ b/source/Target/StackFrame.cpp
@@ -70,7 +70,8 @@ StackFrame::StackFrame (const ThreadSP &thread_sp,
m_is_history_frame (is_history_frame),
m_variable_list_sp (),
m_variable_list_value_objects (),
- m_disassembly ()
+ m_disassembly (),
+ m_mutex (Mutex::eMutexTypeRecursive)
{
// If we don't have a CFA value, use the frame index for our StackID so that recursive
// functions properly aren't confused with one another on a history stack.
@@ -109,7 +110,8 @@ StackFrame::StackFrame (const ThreadSP &thread_sp,
m_is_history_frame (false),
m_variable_list_sp (),
m_variable_list_value_objects (),
- m_disassembly ()
+ m_disassembly (),
+ m_mutex (Mutex::eMutexTypeRecursive)
{
if (sc_ptr != NULL)
{
@@ -148,7 +150,8 @@ StackFrame::StackFrame (const ThreadSP &thread_sp,
m_is_history_frame (false),
m_variable_list_sp (),
m_variable_list_value_objects (),
- m_disassembly ()
+ m_disassembly (),
+ m_mutex (Mutex::eMutexTypeRecursive)
{
if (sc_ptr != NULL)
{
@@ -189,6 +192,7 @@ StackFrame::~StackFrame()
StackID&
StackFrame::GetStackID()
{
+ Mutex::Locker locker(m_mutex);
// Make sure we have resolved the StackID object's symbol context scope if
// we already haven't looked it up.
@@ -235,6 +239,7 @@ StackFrame::GetFrameIndex () const
void
StackFrame::SetSymbolContextScope (SymbolContextScope *symbol_scope)
{
+ Mutex::Locker locker(m_mutex);
m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE);
m_id.SetSymbolContextScope (symbol_scope);
}
@@ -242,6 +247,7 @@ StackFrame::SetSymbolContextScope (SymbolContextScope *symbol_scope)
const Address&
StackFrame::GetFrameCodeAddress()
{
+ Mutex::Locker locker(m_mutex);
if (m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR) && !m_frame_code_addr.IsSectionOffset())
{
m_flags.Set (RESOLVED_FRAME_CODE_ADDR);
@@ -272,6 +278,7 @@ StackFrame::GetFrameCodeAddress()
bool
StackFrame::ChangePC (addr_t pc)
{
+ Mutex::Locker locker(m_mutex);
// We can't change the pc value of a history stack frame - it is immutable.
if (m_is_history_frame)
return false;
@@ -287,6 +294,7 @@ StackFrame::ChangePC (addr_t pc)
const char *
StackFrame::Disassemble ()
{
+ Mutex::Locker locker(m_mutex);
if (m_disassembly.GetSize() == 0)
{
ExecutionContext exe_ctx (shared_from_this());
@@ -346,6 +354,7 @@ StackFrame::GetFrameBlock ()
const SymbolContext&
StackFrame::GetSymbolContext (uint32_t resolve_scope)
{
+ Mutex::Locker locker(m_mutex);
// Copy our internal symbol context into "sc".
if ((m_flags.Get() & resolve_scope) != resolve_scope)
{
@@ -375,7 +384,31 @@ StackFrame::GetSymbolContext (uint32_t resolve_scope)
{
addr_t offset = lookup_addr.GetOffset();
if (offset > 0)
+ {
lookup_addr.SetOffset(offset - 1);
+
+ }
+ else
+ {
+ // lookup_addr is the start of a section. We need
+ // do the math on the actual load address and re-compute
+ // the section. We're working with a 'noreturn' function
+ // at the end of a section.
+ ThreadSP thread_sp (GetThread());
+ if (thread_sp)
+ {
+ TargetSP target_sp (thread_sp->CalculateTarget());
+ if (target_sp)
+ {
+ addr_t addr_minus_one = lookup_addr.GetLoadAddress(target_sp.get()) - 1;
+ lookup_addr.SetLoadAddress (addr_minus_one, target_sp.get());
+ }
+ else
+ {
+ lookup_addr.SetOffset(offset - 1);
+ }
+ }
+ }
}
@@ -504,6 +537,7 @@ StackFrame::GetSymbolContext (uint32_t resolve_scope)
VariableList *
StackFrame::GetVariableList (bool get_file_globals)
{
+ Mutex::Locker locker(m_mutex);
if (m_flags.IsClear(RESOLVED_VARIABLES))
{
m_flags.Set(RESOLVED_VARIABLES);
@@ -544,6 +578,7 @@ StackFrame::GetVariableList (bool get_file_globals)
VariableListSP
StackFrame::GetInScopeVariableList (bool get_file_globals)
{
+ Mutex::Locker locker(m_mutex);
// We can't fetch variable information for a history stack frame.
if (m_is_history_frame)
return VariableListSP();
@@ -680,8 +715,8 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
// Make sure we aren't trying to deref an objective
// C ivar if this is not allowed
const uint32_t pointer_type_flags = valobj_sp->GetClangType().GetTypeInfo (NULL);
- if ((pointer_type_flags & ClangASTType::eTypeIsObjC) &&
- (pointer_type_flags & ClangASTType::eTypeIsPointer))
+ if ((pointer_type_flags & eTypeIsObjC) &&
+ (pointer_type_flags & eTypeIsPointer))
{
// This was an objective C object pointer and
// it was requested we skip any fragile ivars
@@ -1142,6 +1177,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
bool
StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr)
{
+ Mutex::Locker locker(m_mutex);
if (m_cfa_is_valid == false)
{
m_frame_base_error.SetErrorString("No frame base available for this historical stack frame.");
@@ -1191,6 +1227,7 @@ StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr)
RegisterContextSP
StackFrame::GetRegisterContext ()
{
+ Mutex::Locker locker(m_mutex);
if (!m_reg_context_sp)
{
ThreadSP thread_sp (GetThread());
@@ -1211,6 +1248,7 @@ StackFrame::HasDebugInformation ()
ValueObjectSP
StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic)
{
+ Mutex::Locker locker(m_mutex);
ValueObjectSP valobj_sp;
if (m_is_history_frame)
{
@@ -1246,6 +1284,7 @@ StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp, Dynam
ValueObjectSP
StackFrame::TrackGlobalVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic)
{
+ Mutex::Locker locker(m_mutex);
if (m_is_history_frame)
return ValueObjectSP();
@@ -1365,17 +1404,20 @@ StackFrame::Dump (Stream *strm, bool show_frame_index, bool show_fullpaths)
GetSymbolContext(eSymbolContextEverything);
const bool show_module = true;
const bool show_inline = true;
+ const bool show_function_arguments = true;
m_sc.DumpStopContext (strm,
exe_ctx.GetBestExecutionContextScope(),
GetFrameCodeAddress(),
show_fullpaths,
show_module,
- show_inline);
+ show_inline,
+ show_function_arguments);
}
void
StackFrame::UpdateCurrentFrameFromPreviousFrame (StackFrame &prev_frame)
{
+ Mutex::Locker locker(m_mutex);
assert (GetStackID() == prev_frame.GetStackID()); // TODO: remove this after some testing
m_variable_list_sp = prev_frame.m_variable_list_sp;
m_variable_list_value_objects.Swap (prev_frame.m_variable_list_value_objects);
@@ -1387,6 +1429,7 @@ StackFrame::UpdateCurrentFrameFromPreviousFrame (StackFrame &prev_frame)
void
StackFrame::UpdatePreviousFrameFromCurrentFrame (StackFrame &curr_frame)
{
+ Mutex::Locker locker(m_mutex);
assert (GetStackID() == curr_frame.GetStackID()); // TODO: remove this after some testing
m_id.SetPC (curr_frame.m_id.GetPC()); // Update the Stack ID PC value
assert (GetThread() == curr_frame.GetThread());
diff --git a/source/Target/StackFrameList.cpp b/source/Target/StackFrameList.cpp
index 99234dc61f1d..9a132618288d 100644
--- a/source/Target/StackFrameList.cpp
+++ b/source/Target/StackFrameList.cpp
@@ -288,8 +288,8 @@ StackFrameList::GetFramesUpTo(uint32_t end_idx)
do
{
uint32_t idx = m_concrete_frames_fetched++;
- lldb::addr_t pc;
- lldb::addr_t cfa;
+ lldb::addr_t pc = LLDB_INVALID_ADDRESS;
+ lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
if (idx == 0)
{
// We might have already created frame zero, only create it
@@ -625,11 +625,14 @@ StackFrameList::GetFrameWithStackID (const StackID &stack_id)
if (begin != end)
{
collection::const_iterator pos = std::lower_bound (begin, end, stack_id, CompareStackID);
- if (pos != end && (*pos)->GetStackID() == stack_id)
- return *pos;
+ if (pos != end)
+ {
+ if ((*pos)->GetStackID() == stack_id)
+ return *pos;
+ }
- if (m_frames.back()->GetStackID() < stack_id)
- frame_idx = m_frames.size();
+// if (m_frames.back()->GetStackID() < stack_id)
+// frame_idx = m_frames.size();
}
do
{
diff --git a/source/Target/StopInfo.cpp b/source/Target/StopInfo.cpp
index a37a4079ff11..4b57ca65a2df 100644
--- a/source/Target/StopInfo.cpp
+++ b/source/Target/StopInfo.cpp
@@ -40,7 +40,8 @@ StopInfo::StopInfo (Thread &thread, uint64_t value) :
m_resume_id (thread.GetProcess()->GetResumeID()),
m_value (value),
m_override_should_notify (eLazyBoolCalculate),
- m_override_should_stop (eLazyBoolCalculate)
+ m_override_should_stop (eLazyBoolCalculate),
+ m_extended_info()
{
}
@@ -181,6 +182,7 @@ public:
{
ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
StoppointCallbackContext context (event_ptr, exe_ctx, true);
+ bp_site_sp->BumpHitCounts();
m_should_stop = bp_site_sp->ShouldStop (&context);
}
else
@@ -402,10 +404,21 @@ protected:
// Let's copy the breakpoint locations out of the site and store them in a local list. That way if
// one of the breakpoint actions changes the site, then we won't be operating on a bad list.
+ // For safety's sake let's also grab an extra reference to the breakpoint owners of the locations we're
+ // going to examine, since the locations are going to have to get back to their breakpoints, and the
+ // locations don't keep their owners alive. I'm just sticking the BreakpointSP's in a vector since
+ // I'm only really using it to locally increment their retain counts.
BreakpointLocationCollection site_locations;
+ std::vector<lldb::BreakpointSP> location_owners;
+
for (size_t j = 0; j < num_owners; j++)
- site_locations.Add(bp_site_sp->GetOwnerAtIndex(j));
+ {
+ BreakpointLocationSP loc(bp_site_sp->GetOwnerAtIndex(j));
+ site_locations.Add(loc);
+ location_owners.push_back(loc->GetBreakpoint().shared_from_this());
+
+ }
for (size_t j = 0; j < num_owners; j++)
{
@@ -689,14 +702,13 @@ protected:
assert (stored_stop_info_sp.get() == this);
ThreadPlanSP new_plan_sp(thread_sp->QueueThreadPlanForStepSingleInstruction(false, // step-over
- false, // abort_other_plans
- true)); // stop_other_threads
+ false, // abort_other_plans
+ true)); // stop_other_threads
new_plan_sp->SetIsMasterPlan (true);
new_plan_sp->SetOkayToDiscard (false);
new_plan_sp->SetPrivate (true);
process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID());
- process->Resume ();
- process->WaitForProcessToStop (NULL);
+ process->ResumeSynchronous(NULL);
process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID());
thread_sp->SetStopInfo(stored_stop_info_sp);
}
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp
index d2d0b5098555..e9393d1be0b4 100644
--- a/source/Target/Target.cpp
+++ b/source/Target/Target.cpp
@@ -35,6 +35,7 @@
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/ClangASTSource.h"
#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -63,7 +64,7 @@ Target::GetStaticBroadcasterClass ()
//----------------------------------------------------------------------
// Target constructor
//----------------------------------------------------------------------
-Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::PlatformSP &platform_sp) :
+Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::PlatformSP &platform_sp, bool is_dummy_target) :
TargetProperties (this),
Broadcaster (&debugger, Target::GetStaticBroadcasterClass().AsCString()),
ExecutionContextScope (),
@@ -87,7 +88,9 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::Plat
m_stop_hooks (),
m_stop_hook_next_id (0),
m_valid (true),
- m_suppress_stop_hooks (false)
+ m_suppress_stop_hooks (false),
+ m_is_dummy_target(is_dummy_target)
+
{
SetEventName (eBroadcastBitBreakpointChanged, "breakpoint-changed");
SetEventName (eBroadcastBitModulesLoaded, "modules-loaded");
@@ -106,6 +109,24 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::Plat
}
}
+void
+Target::PrimeFromDummyTarget(Target *target)
+{
+ if (!target)
+ return;
+
+ m_stop_hooks = target->m_stop_hooks;
+
+ for (BreakpointSP breakpoint_sp : target->m_breakpoint_list.Breakpoints())
+ {
+ if (breakpoint_sp->IsInternal())
+ continue;
+
+ BreakpointSP new_bp (new Breakpoint (*this, *breakpoint_sp.get()));
+ AddBreakpoint (new_bp, false);
+ }
+}
+
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
@@ -330,7 +351,7 @@ Target::CreateBreakpoint (lldb::addr_t addr, bool internal, bool hardware)
BreakpointSP
Target::CreateBreakpoint (Address &addr, bool internal, bool hardware)
{
- SearchFilterSP filter_sp(new SearchFilterForNonModuleSpecificSearches (shared_from_this()));
+ SearchFilterSP filter_sp(new SearchFilterForUnconstrainedSearches (shared_from_this()));
BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr));
return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, false);
}
@@ -430,7 +451,7 @@ Target::GetSearchFilterForModule (const FileSpec *containingModule)
else
{
if (m_search_filter_sp.get() == NULL)
- m_search_filter_sp.reset (new SearchFilterForNonModuleSpecificSearches (shared_from_this()));
+ m_search_filter_sp.reset (new SearchFilterForUnconstrainedSearches (shared_from_this()));
filter_sp = m_search_filter_sp;
}
return filter_sp;
@@ -449,7 +470,7 @@ Target::GetSearchFilterForModuleList (const FileSpecList *containingModules)
else
{
if (m_search_filter_sp.get() == NULL)
- m_search_filter_sp.reset (new SearchFilterForNonModuleSpecificSearches (shared_from_this()));
+ m_search_filter_sp.reset (new SearchFilterForUnconstrainedSearches (shared_from_this()));
filter_sp = m_search_filter_sp;
}
return filter_sp;
@@ -510,29 +531,35 @@ Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resol
{
bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp, request_hardware, resolve_indirect_symbols));
resolver_sp->SetBreakpoint (bp_sp.get());
+ AddBreakpoint (bp_sp, internal);
+ }
+ return bp_sp;
+}
- if (internal)
- m_internal_breakpoint_list.Add (bp_sp, false);
- else
- m_breakpoint_list.Add (bp_sp, true);
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
- if (log)
- {
- StreamString s;
- bp_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
- log->Printf ("Target::%s (internal = %s) => break_id = %s\n", __FUNCTION__, internal ? "yes" : "no", s.GetData());
- }
+void
+Target::AddBreakpoint (lldb::BreakpointSP bp_sp, bool internal)
+{
+ if (!bp_sp)
+ return;
+ if (internal)
+ m_internal_breakpoint_list.Add (bp_sp, false);
+ else
+ m_breakpoint_list.Add (bp_sp, true);
- bp_sp->ResolveBreakpoint();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ {
+ StreamString s;
+ bp_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Target::%s (internal = %s) => break_id = %s\n", __FUNCTION__, bp_sp->IsInternal() ? "yes" : "no", s.GetData());
}
-
- if (!internal && bp_sp)
+
+ bp_sp->ResolveBreakpoint();
+
+ if (!internal)
{
m_last_created_breakpoint = bp_sp;
}
-
- return bp_sp;
}
bool
@@ -1214,6 +1241,7 @@ Target::ModulesDidUnload (ModuleList &module_list, bool delete_locations)
{
if (m_valid && module_list.GetSize())
{
+ 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);
@@ -1221,7 +1249,7 @@ Target::ModulesDidUnload (ModuleList &module_list, bool delete_locations)
}
bool
-Target::ModuleIsExcludedForNonModuleSpecificSearches (const FileSpec &module_file_spec)
+Target::ModuleIsExcludedForUnconstrainedSearches (const FileSpec &module_file_spec)
{
if (GetBreakpointsConsultPlatformAvoidList())
{
@@ -1235,7 +1263,7 @@ Target::ModuleIsExcludedForNonModuleSpecificSearches (const FileSpec &module_fil
{
for (size_t i = 0; i < num_modules; i++)
{
- if (!ModuleIsExcludedForNonModuleSpecificSearches (matchingModules.GetModuleAtIndex(i)))
+ if (!ModuleIsExcludedForUnconstrainedSearches (matchingModules.GetModuleAtIndex(i)))
return false;
}
return true;
@@ -1245,12 +1273,12 @@ Target::ModuleIsExcludedForNonModuleSpecificSearches (const FileSpec &module_fil
}
bool
-Target::ModuleIsExcludedForNonModuleSpecificSearches (const lldb::ModuleSP &module_sp)
+Target::ModuleIsExcludedForUnconstrainedSearches (const lldb::ModuleSP &module_sp)
{
if (GetBreakpointsConsultPlatformAvoidList())
{
if (m_platform_sp)
- return m_platform_sp->ModuleIsExcludedForNonModuleSpecificSearches (*this, module_sp);
+ return m_platform_sp->ModuleIsExcludedForUnconstrainedSearches (*this, module_sp);
}
return false;
}
@@ -1355,9 +1383,9 @@ Target::ReadMemory (const Address& addr,
ModuleSP addr_module_sp (resolved_addr.GetModule());
if (addr_module_sp && addr_module_sp->GetFileSpec())
error.SetErrorStringWithFormat("%s[0x%" PRIx64 "] can't be resolved, %s in not currently loaded",
- addr_module_sp->GetFileSpec().GetFilename().AsCString(),
+ addr_module_sp->GetFileSpec().GetFilename().AsCString("<Unknown>"),
resolved_addr.GetFileAddress(),
- addr_module_sp->GetFileSpec().GetFilename().AsCString());
+ addr_module_sp->GetFileSpec().GetFilename().AsCString("<Unknonw>"));
else
error.SetErrorStringWithFormat("0x%" PRIx64 " can't be resolved", resolved_addr.GetFileAddress());
}
@@ -1436,7 +1464,12 @@ Target::ReadCStringFromMemory (const Address& addr, char *dst, size_t dst_max_le
Error error;
addr_t curr_addr = addr.GetLoadAddress(this);
Address address(addr);
+
+ // We could call m_process_sp->GetMemoryCacheLineSize() but I don't
+ // think this really needs to be tied to the memory cache subsystem's
+ // cache line size, so leave this as a fixed constant.
const size_t cache_line_size = 512;
+
size_t bytes_left = dst_max_len - 1;
char *curr_dst = dst;
@@ -2006,6 +2039,22 @@ Target::GetSourceManager ()
return *m_source_manager_ap;
}
+ClangModulesDeclVendor *
+Target::GetClangModulesDeclVendor ()
+{
+ static Mutex s_clang_modules_decl_vendor_mutex; // If this is contended we can make it per-target
+
+ {
+ Mutex::Locker clang_modules_decl_vendor_locker(s_clang_modules_decl_vendor_mutex);
+
+ if (!m_clang_modules_decl_vendor_ap)
+ {
+ m_clang_modules_decl_vendor_ap.reset(ClangModulesDeclVendor::Create(*this));
+ }
+ }
+
+ return m_clang_modules_decl_vendor_ap.get();
+}
Target::StopHookSP
Target::CreateStopHook ()
@@ -2173,18 +2222,17 @@ Target::RunStopHooks ()
if (print_thread_header)
result.AppendMessageWithFormat("-- Thread %d\n", exc_ctx_with_reasons[i].GetThreadPtr()->GetIndexID());
-
- bool stop_on_continue = true;
- bool stop_on_error = true;
- bool echo_commands = false;
- bool print_results = true;
- GetDebugger().GetCommandInterpreter().HandleCommands (cur_hook_sp->GetCommands(),
- &exc_ctx_with_reasons[i],
- stop_on_continue,
- stop_on_error,
- echo_commands,
- print_results,
- eLazyBoolNo,
+
+ CommandInterpreterRunOptions options;
+ options.SetStopOnContinue (true);
+ options.SetStopOnError (true);
+ options.SetEchoCommands (false);
+ options.SetPrintResults (true);
+ options.SetAddToHistory (false);
+
+ GetDebugger().GetCommandInterpreter().HandleCommands (cur_hook_sp->GetCommands(),
+ &exc_ctx_with_reasons[i],
+ options,
result);
// If the command started the target going again, we should bag out of
@@ -2279,6 +2327,12 @@ Target::ResolveLoadAddress (addr_t load_addr, Address &so_addr, uint32_t stop_id
}
bool
+Target::ResolveFileAddress (lldb::addr_t file_addr, Address &resolved_addr)
+{
+ return m_images.ResolveFileAddress(file_addr, resolved_addr);
+}
+
+bool
Target::SetSectionLoadAddress (const SectionSP &section_sp, addr_t new_section_load_addr, bool warn_multiple)
{
const addr_t old_section_load_addr = m_section_load_history.GetSectionLoadAddress (SectionLoadHistory::eStopIDNow, section_sp);
@@ -2297,6 +2351,40 @@ Target::SetSectionLoadAddress (const SectionSP &section_sp, addr_t new_section_l
}
+size_t
+Target::UnloadModuleSections (const ModuleList &module_list)
+{
+ size_t section_unload_count = 0;
+ size_t num_modules = module_list.GetSize();
+ for (size_t i=0; i<num_modules; ++i)
+ {
+ section_unload_count += UnloadModuleSections (module_list.GetModuleAtIndex(i));
+ }
+ return section_unload_count;
+}
+
+size_t
+Target::UnloadModuleSections (const lldb::ModuleSP &module_sp)
+{
+ uint32_t stop_id = 0;
+ ProcessSP process_sp(GetProcessSP());
+ if (process_sp)
+ stop_id = process_sp->GetStopID();
+ else
+ stop_id = m_section_load_history.GetLastStopID();
+ SectionList *sections = module_sp->GetSectionList();
+ size_t section_unload_count = 0;
+ if (sections)
+ {
+ const uint32_t num_sections = sections->GetNumSections(0);
+ for (uint32_t i = 0; i < num_sections; ++i)
+ {
+ section_unload_count += m_section_load_history.SetSectionUnloaded(stop_id, sections->GetSectionAtIndex(i));
+ }
+ }
+ return section_unload_count;
+}
+
bool
Target::SetSectionUnloaded (const lldb::SectionSP &section_sp)
{
@@ -2329,10 +2417,14 @@ Target::ClearAllLoadedSections ()
Error
-Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
+Target::Launch (ProcessLaunchInfo &launch_info, Stream *stream)
{
Error error;
-
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET));
+
+ if (log)
+ log->Printf ("Target::%s() called for %s", __FUNCTION__, launch_info.GetExecutableFile().GetPath().c_str ());
+
StateType state = eStateInvalid;
// Scope to temporarily get the process state in case someone has manually
@@ -2342,7 +2434,16 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
ProcessSP process_sp (GetProcessSP());
if (process_sp)
+ {
state = process_sp->GetState();
+ if (log)
+ log->Printf ("Target::%s the process exists, and its current state is %s", __FUNCTION__, StateAsCString (state));
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Target::%s the process instance doesn't currently exist.", __FUNCTION__);
+ }
}
launch_info.GetFlags().Set (eLaunchFlagDebug);
@@ -2358,6 +2459,13 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
// Finalize the file actions, and if none were given, default to opening
// up a pseudo terminal
const bool default_to_use_pty = platform_sp ? platform_sp->IsHost() : false;
+ if (log)
+ log->Printf ("Target::%s have platform=%s, platform_sp->IsHost()=%s, default_to_use_pty=%s",
+ __FUNCTION__,
+ platform_sp ? "true" : "false",
+ platform_sp ? (platform_sp->IsHost () ? "true" : "false") : "n/a",
+ default_to_use_pty ? "true" : "false");
+
launch_info.FinalizeFileActions (this, default_to_use_pty);
if (state == eStateConnected)
@@ -2375,14 +2483,19 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
// If we're not already connected to the process, and if we have a platform that can launch a process for debugging, go ahead and do that here.
if (state != eStateConnected && platform_sp && platform_sp->CanDebugProcess ())
{
+ if (log)
+ log->Printf ("Target::%s asking the platform to debug the process", __FUNCTION__);
+
m_process_sp = GetPlatform()->DebugProcess (launch_info,
debugger,
this,
- listener,
error);
}
else
{
+ if (log)
+ log->Printf ("Target::%s the platform doesn't know how to debug a process, getting a process plugin to do this for us.", __FUNCTION__);
+
if (state == eStateConnected)
{
assert(m_process_sp);
@@ -2391,7 +2504,7 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
{
// Use a Process plugin to construct the process.
const char *plugin_name = launch_info.GetProcessPluginName();
- CreateProcess (listener, plugin_name, NULL);
+ CreateProcess (launch_info.GetListenerForProcess(debugger), plugin_name, NULL);
}
// Since we didn't have a platform launch the process, launch it here.
@@ -2411,8 +2524,8 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == false)
{
ListenerSP hijack_listener_sp (launch_info.GetHijackListener());
-
- StateType state = m_process_sp->WaitForProcessToStop (NULL, NULL, false, hijack_listener_sp.get());
+
+ StateType state = m_process_sp->WaitForProcessToStop (NULL, NULL, false, hijack_listener_sp.get(), NULL);
if (state == eStateStopped)
{
@@ -2430,7 +2543,7 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
if (synchronous_execution)
{
- state = m_process_sp->WaitForProcessToStop (NULL, NULL, true, hijack_listener_sp.get());
+ 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))
{
@@ -2447,7 +2560,7 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
}
else if (state == eStateExited)
{
- bool with_shell = launch_info.GetShell();
+ bool with_shell = !!launch_info.GetShell();
const int exit_status = m_process_sp->GetExitStatus();
const char *exit_desc = m_process_sp->GetExitDescription();
#define LAUNCH_SHELL_MESSAGE "\n'r' and 'run' are aliases that default to launching through a shell.\nTry launching without going through a shell by using 'process launch'."
@@ -2632,7 +2745,7 @@ g_properties[] =
{
{ "default-arch" , OptionValue::eTypeArch , true , 0 , NULL, NULL, "Default architecture to choose, when there's a choice." },
{ "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, eNoDynamicValues , NULL, g_dynamic_value_types, "Should printed values be shown as their dynamic value." },
+ { "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." },
{ "skip-prologue" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "Skip function prologues when setting breakpoints by name." },
{ "source-map" , OptionValue::eTypePathMap , false, 0 , NULL, NULL, "Source path remappings used to track the change of location between a source file when built, and "
@@ -2656,12 +2769,13 @@ g_properties[] =
{ "detach-on-error" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "debugserver will detach (rather than killing) a process if it loses connection with lldb." },
{ "disable-aslr" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "Disable Address Space Layout Randomization (ASLR)" },
{ "disable-stdio" , OptionValue::eTypeBoolean , false, false , NULL, NULL, "Disable stdin/stdout for process (e.g. for a GUI application)" },
- { "inline-breakpoint-strategy" , OptionValue::eTypeEnum , false, eInlineBreakpointsHeaders , NULL, g_inline_breakpoint_enums, "The strategy to use when settings breakpoints by file and line. "
+ { "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. "
"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 we try to minimize the "
- "times we look for inlined locations. This setting allows you to control exactly which strategy is used when settings "
+ "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. "
+ "This setting allows you to control exactly which strategy is used when setting "
"file and line breakpoints." },
// FIXME: This is the wrong way to do per-architecture settings, but we don't have a general per architecture settings system in place yet.
{ "x86-disassembly-flavor" , OptionValue::eTypeEnum , false, eX86DisFlavorDefault, NULL, g_x86_dis_flavor_value_types, "The default disassembly flavor to use for x86 or x86-64 targets." },
diff --git a/source/Target/TargetList.cpp b/source/Target/TargetList.cpp
index 5ee75ff74449..28ad47e3d81d 100644
--- a/source/Target/TargetList.cpp
+++ b/source/Target/TargetList.cpp
@@ -21,6 +21,7 @@
#include "lldb/Core/State.h"
#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/OptionGroupPlatform.h"
#include "lldb/Symbol/ObjectFile.h"
@@ -69,6 +70,41 @@ TargetList::CreateTarget (Debugger &debugger,
const OptionGroupPlatform *platform_options,
TargetSP &target_sp)
{
+ return CreateTargetInternal (debugger,
+ user_exe_path,
+ triple_cstr,
+ get_dependent_files,
+ platform_options,
+ target_sp,
+ false);
+}
+
+Error
+TargetList::CreateTarget (Debugger &debugger,
+ const char *user_exe_path,
+ const ArchSpec& specified_arch,
+ bool get_dependent_files,
+ PlatformSP &platform_sp,
+ TargetSP &target_sp)
+{
+ return CreateTargetInternal (debugger,
+ user_exe_path,
+ specified_arch,
+ get_dependent_files,
+ platform_sp,
+ target_sp,
+ false);
+}
+
+Error
+TargetList::CreateTargetInternal (Debugger &debugger,
+ const char *user_exe_path,
+ const char *triple_cstr,
+ bool get_dependent_files,
+ const OptionGroupPlatform *platform_options,
+ TargetSP &target_sp,
+ bool is_dummy_target)
+{
Error error;
PlatformSP platform_sp;
@@ -170,7 +206,7 @@ TargetList::CreateTarget (Debugger &debugger,
typedef std::vector<PlatformSP> PlatformList;
PlatformList platforms;
- PlatformSP host_platform_sp = Platform::GetDefaultPlatform();
+ PlatformSP host_platform_sp = Platform::GetHostPlatform();
for (size_t i=0; i<num_specs; ++i)
{
ModuleSpec module_spec;
@@ -258,7 +294,11 @@ TargetList::CreateTarget (Debugger &debugger,
if (!prefer_platform_arch && arch.IsValid())
{
if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
+ {
platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
+ if (platform_sp)
+ debugger.GetPlatformList().SetSelectedPlatform(platform_sp);
+ }
}
else if (platform_arch.IsValid())
{
@@ -266,30 +306,69 @@ TargetList::CreateTarget (Debugger &debugger,
// 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);
+ }
}
}
if (!platform_arch.IsValid())
platform_arch = arch;
- error = TargetList::CreateTarget (debugger,
- user_exe_path,
- platform_arch,
- get_dependent_files,
- platform_sp,
- target_sp);
+ error = TargetList::CreateTargetInternal (debugger,
+ user_exe_path,
+ platform_arch,
+ get_dependent_files,
+ platform_sp,
+ target_sp,
+ is_dummy_target);
return error;
}
+lldb::TargetSP
+TargetList::GetDummyTarget (lldb_private::Debugger &debugger)
+{
+ // FIXME: Maybe the dummy target should be per-Debugger
+ if (!m_dummy_target_sp || !m_dummy_target_sp->IsValid())
+ {
+ ArchSpec arch(Target::GetDefaultArchitecture());
+ if (!arch.IsValid())
+ arch = HostInfo::GetArchitecture();
+ Error err = CreateDummyTarget(debugger,
+ arch.GetTriple().getTriple().c_str(),
+ m_dummy_target_sp);
+ }
+
+ return m_dummy_target_sp;
+}
+
Error
-TargetList::CreateTarget (Debugger &debugger,
- const char *user_exe_path,
- const ArchSpec& specified_arch,
- bool get_dependent_files,
- PlatformSP &platform_sp,
- TargetSP &target_sp)
+TargetList::CreateDummyTarget (Debugger &debugger,
+ const char *specified_arch_name,
+ lldb::TargetSP &target_sp)
{
+ PlatformSP host_platform_sp(Platform::GetHostPlatform());
+ return CreateTargetInternal (debugger,
+ (const char *) nullptr,
+ specified_arch_name,
+ false,
+ (const OptionGroupPlatform *) nullptr,
+ target_sp,
+ true);
+}
+
+Error
+TargetList::CreateTargetInternal (Debugger &debugger,
+ const char *user_exe_path,
+ const ArchSpec& specified_arch,
+ bool get_dependent_files,
+ lldb::PlatformSP &platform_sp,
+ lldb::TargetSP &target_sp,
+ bool is_dummy_target)
+{
+
Timer scoped_timer (__PRETTY_FUNCTION__,
"TargetList::CreateTarget (file = '%s', arch = '%s')",
user_exe_path,
@@ -332,7 +411,7 @@ TargetList::CreateTarget (Debugger &debugger,
if (file.GetFileType() == FileSpec::eFileTypeDirectory)
user_exe_path_is_bundle = true;
- if (file.IsRelativeToCurrentWorkingDirectory())
+ if (file.IsRelativeToCurrentWorkingDirectory() && user_exe_path)
{
// Ignore paths that start with "./" and "../"
if (!((user_exe_path[0] == '.' && user_exe_path[1] == '/') ||
@@ -355,8 +434,8 @@ TargetList::CreateTarget (Debugger &debugger,
if (platform_sp)
{
FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
- error = platform_sp->ResolveExecutable (file,
- arch,
+ ModuleSpec module_spec(file, arch);
+ error = platform_sp->ResolveExecutable (module_spec,
exe_module_sp,
executable_search_paths.GetSize() ? &executable_search_paths : NULL);
}
@@ -378,7 +457,7 @@ TargetList::CreateTarget (Debugger &debugger,
}
return error;
}
- target_sp.reset(new Target(debugger, arch, platform_sp));
+ target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
target_sp->SetExecutableModule (exe_module_sp, get_dependent_files);
if (user_exe_path_is_bundle)
exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path, sizeof(resolved_bundle_exe_path));
@@ -388,7 +467,7 @@ TargetList::CreateTarget (Debugger &debugger,
{
// No file was specified, just create an empty target with any arch
// if a valid arch was specified
- target_sp.reset(new Target(debugger, arch, platform_sp));
+ target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
}
if (target_sp)
@@ -415,11 +494,20 @@ TargetList::CreateTarget (Debugger &debugger,
file_dir.GetDirectory() = file.GetDirectory();
target_sp->GetExecutableSearchPaths ().Append (file_dir);
}
- Mutex::Locker locker(m_target_list_mutex);
- m_selected_target_idx = m_target_list.size();
- m_target_list.push_back(target_sp);
-
-
+
+ // Don't put the dummy target in the target list, it's held separately.
+ if (!is_dummy_target)
+ {
+ Mutex::Locker locker(m_target_list_mutex);
+ m_selected_target_idx = m_target_list.size();
+ m_target_list.push_back(target_sp);
+ // Now prime this from the dummy target:
+ target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget());
+ }
+ else
+ {
+ m_dummy_target_sp = target_sp;
+ }
}
return error;
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
index a445517da6a8..b532d8d71c8f 100644
--- a/source/Target/Thread.cpp
+++ b/source/Target/Thread.cpp
@@ -32,6 +32,7 @@
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Target/ThreadPlanBase.h"
+#include "lldb/Target/ThreadPlanPython.h"
#include "lldb/Target/ThreadPlanStepInstruction.h"
#include "lldb/Target/ThreadPlanStepOut.h"
#include "lldb/Target/ThreadPlanStepOverBreakpoint.h"
@@ -43,7 +44,7 @@
#include "lldb/Target/ThreadSpec.h"
#include "lldb/Target/Unwind.h"
#include "Plugins/Process/Utility/UnwindLLDB.h"
-#include "UnwindMacOSXFrameBackchain.h"
+#include "Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h"
using namespace lldb;
@@ -278,6 +279,7 @@ Thread::Thread (Process &process, lldb::tid_t tid, bool use_invalid_index_id) :
m_process_wp (process.shared_from_this()),
m_stop_info_sp (),
m_stop_info_stop_id (0),
+ m_stop_info_override_stop_id (0),
m_index_id (use_invalid_index_id ? LLDB_INVALID_INDEX32 : process.GetNextThreadIndexID(tid)),
m_reg_context_sp (),
m_state (eStateUnloaded),
@@ -465,6 +467,24 @@ Thread::GetPrivateStopInfo ()
SetStopInfo (StopInfoSP());
}
}
+
+ // The stop info can be manually set by calling Thread::SetStopInfo()
+ // prior to this function ever getting called, so we can't rely on
+ // "m_stop_info_stop_id != process_stop_id" as the condition for
+ // the if statement below, we must also check the stop info to see
+ // if we need to override it. See the header documentation in
+ // Process::GetStopInfoOverrideCallback() for more information on
+ // the stop info override callback.
+ if (m_stop_info_override_stop_id != process_stop_id)
+ {
+ m_stop_info_override_stop_id = process_stop_id;
+ if (m_stop_info_sp)
+ {
+ ArchSpec::StopInfoOverrideCallbackType callback = GetProcess()->GetStopInfoOverrideCallback();
+ if (callback)
+ callback(*this);
+ }
+ }
}
return m_stop_info_sp;
}
@@ -642,7 +662,8 @@ Thread::SetupForResume ()
lldb::RegisterContextSP reg_ctx_sp (GetRegisterContext());
if (reg_ctx_sp)
{
- BreakpointSiteSP bp_site_sp = GetProcess()->GetBreakpointSiteList().FindByAddress(reg_ctx_sp->GetPC());
+ const addr_t thread_pc = reg_ctx_sp->GetPC();
+ BreakpointSiteSP bp_site_sp = GetProcess()->GetBreakpointSiteList().FindByAddress(thread_pc);
if (bp_site_sp)
{
// Note, don't assume there's a ThreadPlanStepOverBreakpoint, the target may not require anything
@@ -650,19 +671,30 @@ Thread::SetupForResume ()
ThreadPlan *cur_plan = GetCurrentPlan();
- if (cur_plan->GetKind() != ThreadPlan::eKindStepOverBreakpoint)
+ bool push_step_over_bp_plan = false;
+ if (cur_plan->GetKind() == ThreadPlan::eKindStepOverBreakpoint)
{
- ThreadPlanStepOverBreakpoint *step_bp_plan = new ThreadPlanStepOverBreakpoint (*this);
- if (step_bp_plan)
+ ThreadPlanStepOverBreakpoint *bp_plan = (ThreadPlanStepOverBreakpoint *)cur_plan;
+ if (bp_plan->GetBreakpointLoadAddress() != thread_pc)
+ push_step_over_bp_plan = true;
+ }
+ else
+ push_step_over_bp_plan = true;
+
+ if (push_step_over_bp_plan)
+ {
+ ThreadPlanSP step_bp_plan_sp (new ThreadPlanStepOverBreakpoint (*this));
+ if (step_bp_plan_sp)
{
- ThreadPlanSP step_bp_plan_sp;
- step_bp_plan->SetPrivate (true);
+ ;
+ step_bp_plan_sp->SetPrivate (true);
if (GetCurrentPlan()->RunState() != eStateStepping)
{
+ ThreadPlanStepOverBreakpoint *step_bp_plan
+ = static_cast<ThreadPlanStepOverBreakpoint *>(step_bp_plan_sp.get());
step_bp_plan->SetAutoContinue(true);
}
- step_bp_plan_sp.reset (step_bp_plan);
QueueThreadPlan (step_bp_plan_sp, false);
}
}
@@ -941,30 +973,30 @@ Thread::ShouldStop (Event* event_ptr)
if (over_ride_stop)
should_stop = false;
- // One other potential problem is that we set up a master plan, then stop in before it is complete - for instance
- // by hitting a breakpoint during a step-over - then do some step/finish/etc operations that wind up
- // past the end point condition of the initial plan. We don't want to strand the original plan on the stack,
- // This code clears stale plans off the stack.
+ }
+
+ // One other potential problem is that we set up a master plan, then stop in before it is complete - for instance
+ // by hitting a breakpoint during a step-over - then do some step/finish/etc operations that wind up
+ // past the end point condition of the initial plan. We don't want to strand the original plan on the stack,
+ // This code clears stale plans off the stack.
- if (should_stop)
+ if (should_stop)
+ {
+ ThreadPlan *plan_ptr = GetCurrentPlan();
+ while (!PlanIsBasePlan(plan_ptr))
{
- ThreadPlan *plan_ptr = GetCurrentPlan();
- while (!PlanIsBasePlan(plan_ptr))
- {
- bool stale = plan_ptr->IsPlanStale ();
- ThreadPlan *examined_plan = plan_ptr;
- plan_ptr = GetPreviousPlan (examined_plan);
+ bool stale = plan_ptr->IsPlanStale ();
+ ThreadPlan *examined_plan = plan_ptr;
+ plan_ptr = GetPreviousPlan (examined_plan);
- if (stale)
- {
- if (log)
- log->Printf("Plan %s being discarded in cleanup, it says it is already done.",
- examined_plan->GetName());
- DiscardThreadPlansUpToPlan(examined_plan);
- }
+ if (stale)
+ {
+ if (log)
+ log->Printf("Plan %s being discarded in cleanup, it says it is already done.",
+ examined_plan->GetName());
+ DiscardThreadPlansUpToPlan(examined_plan);
}
}
-
}
if (log)
@@ -1290,6 +1322,36 @@ Thread::SetTracer (lldb::ThreadPlanTracerSP &tracer_sp)
m_plan_stack[i]->SetThreadPlanTracer(tracer_sp);
}
+bool
+Thread::DiscardUserThreadPlansUpToIndex (uint32_t thread_index)
+{
+ // Count the user thread plans from the back end to get the number of the one we want
+ // to discard:
+
+ uint32_t idx = 0;
+ ThreadPlan *up_to_plan_ptr = nullptr;
+
+ for (ThreadPlanSP plan_sp : m_plan_stack)
+ {
+ if (plan_sp->GetPrivate())
+ continue;
+ if (idx == thread_index)
+ {
+ up_to_plan_ptr = plan_sp.get();
+ break;
+ }
+ else
+ idx++;
+ }
+
+ if (up_to_plan_ptr == nullptr)
+ return false;
+
+ DiscardThreadPlansUpToPlan(up_to_plan_ptr);
+ return true;
+}
+
+
void
Thread::DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp)
{
@@ -1483,18 +1545,16 @@ Thread::QueueThreadPlanForStepInRange
LazyBool step_out_avoids_code_without_debug_info
)
{
- ThreadPlanSP thread_plan_sp;
- ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this,
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepInRange (*this,
range,
addr_context,
stop_other_threads,
step_in_avoids_code_without_debug_info,
- step_out_avoids_code_without_debug_info);
+ step_out_avoids_code_without_debug_info));
+ ThreadPlanStepInRange *plan = static_cast<ThreadPlanStepInRange *>(thread_plan_sp.get());
if (step_in_target)
plan->SetStepInTarget(step_in_target);
-
- thread_plan_sp.reset (plan);
QueueThreadPlan (thread_plan_sp, abort_other_plans);
return thread_plan_sp;
@@ -1546,17 +1606,18 @@ Thread::QueueThreadPlanForStepOutNoShouldStop
uint32_t frame_idx
)
{
- ThreadPlanStepOut *new_plan = new ThreadPlanStepOut (*this,
+ ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut (*this,
addr_context,
first_insn,
stop_other_threads,
stop_vote,
run_vote,
frame_idx,
- eLazyBoolNo);
+ eLazyBoolNo));
+
+ ThreadPlanStepOut *new_plan = static_cast<ThreadPlanStepOut *>(thread_plan_sp.get());
new_plan->ClearShouldStopHereCallbacks();
- ThreadPlanSP thread_plan_sp(new_plan);
-
+
if (thread_plan_sp->ValidatePlan(NULL))
{
QueueThreadPlan (thread_plan_sp, abort_other_plans);
@@ -1602,61 +1663,105 @@ Thread::QueueThreadPlanForStepUntil (bool abort_other_plans,
}
+lldb::ThreadPlanSP
+Thread::QueueThreadPlanForStepScripted (bool abort_other_plans,
+ const char *class_name,
+ bool stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanPython (*this, class_name));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ // This seems a little funny, but I don't want to have to split up the constructor and the
+ // DidPush in the scripted plan, that seems annoying.
+ // That means the constructor has to be in DidPush.
+ // So I have to validate the plan AFTER pushing it, and then take it off again...
+ if (!thread_plan_sp->ValidatePlan(nullptr))
+ {
+ DiscardThreadPlansUpToPlan(thread_plan_sp);
+ return ThreadPlanSP();
+ }
+ else
+ return thread_plan_sp;
+
+}
+
uint32_t
Thread::GetIndexID () const
{
return m_index_id;
}
-void
-Thread::DumpThreadPlans (lldb_private::Stream *s) const
+static void
+PrintPlanElement (Stream *s, const ThreadPlanSP &plan, lldb::DescriptionLevel desc_level, int32_t elem_idx)
{
- uint32_t stack_size = m_plan_stack.size();
- int i;
- s->Indent();
- s->Printf ("Plan Stack for thread #%u: tid = 0x%4.4" PRIx64 ", stack_size = %d\n", GetIndexID(), GetID(), stack_size);
- for (i = stack_size - 1; i >= 0; i--)
- {
s->IndentMore();
s->Indent();
- s->Printf ("Element %d: ", i);
- m_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->Printf ("Element %d: ", elem_idx);
+ plan->GetDescription (s, desc_level);
s->EOL();
s->IndentLess();
+}
+
+static void
+PrintPlanStack (Stream *s, const std::vector<lldb::ThreadPlanSP> &plan_stack, lldb::DescriptionLevel desc_level, bool include_internal)
+{
+ int32_t print_idx = 0;
+ for (ThreadPlanSP plan_sp : plan_stack)
+ {
+ if (include_internal || !plan_sp->GetPrivate())
+ {
+ PrintPlanElement (s, plan_sp, desc_level, print_idx++);
+ }
}
+}
- stack_size = m_completed_plan_stack.size();
- if (stack_size > 0)
+void
+Thread::DumpThreadPlans (Stream *s,
+ lldb::DescriptionLevel desc_level,
+ bool include_internal,
+ bool ignore_boring_threads) const
+{
+ uint32_t stack_size;
+
+ if (ignore_boring_threads)
{
- s->Indent();
- s->Printf ("Completed Plan Stack: %d elements.\n", stack_size);
- for (i = stack_size - 1; i >= 0; i--)
+ uint32_t stack_size = m_plan_stack.size();
+ uint32_t completed_stack_size = m_completed_plan_stack.size();
+ uint32_t discarded_stack_size = m_discarded_plan_stack.size();
+ if (stack_size == 1 && completed_stack_size == 0 && discarded_stack_size == 0)
{
+ s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID());
s->IndentMore();
s->Indent();
- s->Printf ("Element %d: ", i);
- m_completed_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
- s->EOL();
+ s->Printf("No active thread plans\n");
s->IndentLess();
+ return;
}
}
+ s->Indent();
+ s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID());
+ s->IndentMore();
+ s->Indent();
+ s->Printf ("Active plan stack:\n");
+ PrintPlanStack (s, m_plan_stack, desc_level, include_internal);
+
+ stack_size = m_completed_plan_stack.size();
+ if (stack_size > 0)
+ {
+ s->Indent();
+ s->Printf ("Completed Plan Stack:\n");
+ PrintPlanStack (s, m_completed_plan_stack, desc_level, include_internal);
+ }
+
stack_size = m_discarded_plan_stack.size();
if (stack_size > 0)
{
s->Indent();
- s->Printf ("Discarded Plan Stack: %d elements.\n", stack_size);
- for (i = stack_size - 1; i >= 0; i--)
- {
- s->IndentMore();
- s->Indent();
- s->Printf ("Element %d: ", i);
- m_discarded_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
- s->EOL();
- s->IndentLess();
- }
+ s->Printf ("Discarded Plan Stack:\n");
+ PrintPlanStack (s, m_discarded_plan_stack, desc_level, include_internal);
}
+ s->IndentLess();
}
TargetSP
@@ -1785,7 +1890,7 @@ Thread::ReturnFromFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return
// FIXME: ValueObject::Cast doesn't currently work correctly, at least not for scalars.
// Turn that back on when that works.
- if (0 && sc.function != NULL)
+ if (/* DISABLES CODE */ (0) && sc.function != NULL)
{
Type *function_type = sc.function->GetType();
if (function_type)
@@ -2011,6 +2116,7 @@ Thread::StopReasonAsCString (lldb::StopReason reason)
case eStopReasonExec: return "exec";
case eStopReasonPlanComplete: return "plan complete";
case eStopReasonThreadExiting: return "thread exiting";
+ case eStopReasonInstrumentation: return "instrumentation break";
}
@@ -2090,17 +2196,28 @@ Thread::GetStatus (Stream &strm, uint32_t start_frame, uint32_t num_frames, uint
}
bool
-Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_json)
+Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_json_thread, bool print_json_stopinfo)
{
DumpUsingSettingsFormat (strm, 0);
strm.Printf("\n");
StructuredData::ObjectSP thread_info = GetExtendedInfo();
-
- if (thread_info && print_json)
+ StructuredData::ObjectSP stop_info = m_stop_info_sp->GetExtendedInfo();
+
+ if (print_json_thread || print_json_stopinfo)
{
- thread_info->Dump (strm);
- strm.Printf("\n");
+ if (thread_info && print_json_thread)
+ {
+ thread_info->Dump (strm);
+ strm.Printf("\n");
+ }
+
+ if (stop_info && print_json_stopinfo)
+ {
+ stop_info->Dump (strm);
+ strm.Printf("\n");
+ }
+
return true;
}
@@ -2194,6 +2311,8 @@ Thread::GetUnwinder ()
case llvm::Triple::aarch64:
case llvm::Triple::thumb:
case llvm::Triple::mips64:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
case llvm::Triple::hexagon:
m_unwinder_ap.reset (new UnwindLLDB (*this));
break;
diff --git a/source/Target/ThreadCollection.cpp b/source/Target/ThreadCollection.cpp
new file mode 100644
index 000000000000..dc1e38e02420
--- /dev/null
+++ b/source/Target/ThreadCollection.cpp
@@ -0,0 +1,62 @@
+//===-- ThreadCollection.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>
+
+#include <algorithm>
+
+#include "lldb/Target/ThreadCollection.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadCollection::ThreadCollection() :
+ m_threads(),
+ m_mutex()
+{
+}
+
+ThreadCollection::ThreadCollection(collection threads) :
+ m_threads(threads),
+ m_mutex()
+{
+}
+
+void
+ThreadCollection::AddThread (const ThreadSP &thread_sp)
+{
+ Mutex::Locker locker(GetMutex());
+ m_threads.push_back (thread_sp);
+}
+
+void
+ThreadCollection::InsertThread (const lldb::ThreadSP &thread_sp, uint32_t idx)
+{
+ Mutex::Locker locker(GetMutex());
+ if (idx < m_threads.size())
+ m_threads.insert(m_threads.begin() + idx, thread_sp);
+ else
+ m_threads.push_back (thread_sp);
+}
+
+uint32_t
+ThreadCollection::GetSize ()
+{
+ Mutex::Locker locker(GetMutex());
+ return m_threads.size();
+}
+
+ThreadSP
+ThreadCollection::GetThreadAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker(GetMutex());
+ ThreadSP thread_sp;
+ if (idx < m_threads.size())
+ thread_sp = m_threads[idx];
+ return thread_sp;
+}
diff --git a/source/Target/ThreadList.cpp b/source/Target/ThreadList.cpp
index 7fb16fdac5c0..db4407b4b579 100644
--- a/source/Target/ThreadList.cpp
+++ b/source/Target/ThreadList.cpp
@@ -22,17 +22,17 @@ using namespace lldb;
using namespace lldb_private;
ThreadList::ThreadList (Process *process) :
+ ThreadCollection(),
m_process (process),
m_stop_id (0),
- m_threads(),
m_selected_tid (LLDB_INVALID_THREAD_ID)
{
}
ThreadList::ThreadList (const ThreadList &rhs) :
+ ThreadCollection(),
m_process (rhs.m_process),
m_stop_id (rhs.m_stop_id),
- m_threads (),
m_selected_tid ()
{
// Use the assignment operator since it uses the mutex
@@ -77,25 +77,6 @@ ThreadList::SetStopID (uint32_t stop_id)
m_stop_id = stop_id;
}
-
-void
-ThreadList::AddThread (const ThreadSP &thread_sp)
-{
- Mutex::Locker locker(GetMutex());
- m_threads.push_back(thread_sp);
-}
-
-void
-ThreadList::InsertThread (const lldb::ThreadSP &thread_sp, uint32_t idx)
-{
- Mutex::Locker locker(GetMutex());
- if (idx < m_threads.size())
- m_threads.insert(m_threads.begin() + idx, thread_sp);
- else
- m_threads.push_back (thread_sp);
-}
-
-
uint32_t
ThreadList::GetSize (bool can_update)
{
diff --git a/source/Target/ThreadPlanPython.cpp b/source/Target/ThreadPlanPython.cpp
new file mode 100644
index 000000000000..e196d81c897a
--- /dev/null
+++ b/source/Target/ThreadPlanPython.cpp
@@ -0,0 +1,192 @@
+//===-- ThreadPlan.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/Target/ThreadPlan.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#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"
+#include "lldb/Target/ThreadPlanPython.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanPython
+//----------------------------------------------------------------------
+
+ThreadPlanPython::ThreadPlanPython (Thread &thread, const char *class_name) :
+ ThreadPlan (ThreadPlan::eKindPython,
+ "Python based Thread Plan",
+ thread,
+ eVoteNoOpinion,
+ eVoteNoOpinion),
+ m_class_name (class_name)
+{
+ SetIsMasterPlan (true);
+ SetOkayToDiscard (true);
+ SetPrivate (false);
+}
+
+ThreadPlanPython::~ThreadPlanPython ()
+{
+ // FIXME, do I need to decrement the ref count on this implementation object to make it go away?
+}
+
+bool
+ThreadPlanPython::ValidatePlan (Stream *error)
+{
+ // I have to postpone setting up the implementation till after the constructor because I need to call
+ // shared_from_this, which you can't do in the constructor. So I'll do it here.
+ if (m_implementation_sp)
+ return true;
+ else
+ return false;
+}
+
+void
+ThreadPlanPython::DidPush()
+{
+ // We set up the script side in DidPush, so that it can push other plans in the constructor,
+ // and doesn't have to care about the details of DidPush.
+
+ if (!m_class_name.empty())
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ m_implementation_sp = script_interp->CreateScriptedThreadPlan (m_class_name.c_str(), this->shared_from_this());
+ }
+ }
+}
+
+bool
+ThreadPlanPython::ShouldStop (Event *event_ptr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+
+ bool should_stop = true;
+ if (m_implementation_sp)
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ bool script_error;
+ should_stop = script_interp->ScriptedThreadPlanShouldStop (m_implementation_sp, event_ptr, script_error);
+ if (script_error)
+ SetPlanComplete(false);
+ }
+ }
+ return should_stop;
+}
+
+bool
+ThreadPlanPython::DoPlanExplainsStop (Event *event_ptr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+
+ bool explains_stop = true;
+ if (m_implementation_sp)
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ bool script_error;
+ explains_stop = script_interp->ScriptedThreadPlanExplainsStop (m_implementation_sp, event_ptr, script_error);
+ if (script_error)
+ SetPlanComplete(false);
+ }
+ }
+ return explains_stop;
+}
+
+bool
+ThreadPlanPython::MischiefManaged ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+ bool mischief_managed = true;
+ if (m_implementation_sp)
+ {
+ // I don't really need mischief_managed, since it's simpler to just call SetPlanComplete in should_stop.
+ mischief_managed = IsPlanComplete();
+ if (mischief_managed)
+ m_implementation_sp.reset();
+ }
+ return mischief_managed;
+}
+
+lldb::StateType
+ThreadPlanPython::GetPlanRunState ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__,
+ m_class_name.c_str());
+ lldb::StateType run_state = eStateRunning;
+ if (m_implementation_sp)
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ bool script_error;
+ run_state = script_interp->ScriptedThreadPlanGetRunState (m_implementation_sp, script_error);
+ }
+ }
+ return run_state;
+}
+
+// The ones below are not currently exported to Python.
+
+bool
+ThreadPlanPython::StopOthers ()
+{
+ // For now Python plans run all threads, but we should add some controls for this.
+ return false;
+}
+
+void
+ThreadPlanPython::GetDescription (Stream *s,
+ lldb::DescriptionLevel level)
+{
+ s->Printf ("Python thread plan implemented by class %s.", m_class_name.c_str());
+}
+
+bool
+ThreadPlanPython::WillStop ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+ return true;
+}
diff --git a/source/Target/ThreadPlanStepInRange.cpp b/source/Target/ThreadPlanStepInRange.cpp
index 3e9abef65573..e5f057c183fb 100644
--- a/source/Target/ThreadPlanStepInRange.cpp
+++ b/source/Target/ThreadPlanStepInRange.cpp
@@ -105,7 +105,6 @@ ThreadPlanStepInRange::SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_de
else
GetFlags().Clear (ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
- avoid_nodebug = true;
switch (step_out_avoids_code_without_debug_info)
{
case eLazyBoolYes:
@@ -128,17 +127,31 @@ void
ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
+ {
s->Printf("step in");
- else
+ return;
+ }
+
+ s->Printf ("Stepping in");
+ bool printed_line_info = false;
+ if (m_addr_context.line_entry.IsValid())
+ {
+ s->Printf (" through line ");
+ m_addr_context.line_entry.DumpStopContext (s, false);
+ printed_line_info = true;
+ }
+
+ const char *step_into_target = m_step_into_target.AsCString();
+ if (step_into_target && step_into_target[0] != '\0')
+ s->Printf (" targeting %s", m_step_into_target.AsCString());
+
+ if (!printed_line_info || level == eDescriptionLevelVerbose)
{
- s->Printf ("Stepping through range (stepping into functions): ");
+ s->Printf (" using ranges:");
DumpRanges(s);
- const char *step_into_target = m_step_into_target.AsCString();
- if (step_into_target && step_into_target[0] != '\0')
- s->Printf (" targeting %s.", m_step_into_target.AsCString());
- else
- s->PutChar('.');
}
+
+ s->PutChar('.');
}
bool
@@ -303,6 +316,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
else
{
m_no_more_plans = false;
+ m_sub_plan_sp->SetPrivate(true);
return false;
}
}
diff --git a/source/Target/ThreadPlanStepInstruction.cpp b/source/Target/ThreadPlanStepInstruction.cpp
index fabf63b1e9d6..0f6d7b78a9ce 100644
--- a/source/Target/ThreadPlanStepInstruction.cpp
+++ b/source/Target/ThreadPlanStepInstruction.cpp
@@ -150,7 +150,16 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
- StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0);
+ if (!cur_frame_sp)
+ {
+ if (log)
+ log->Printf ("ThreadPlanStepInstruction couldn't get the 0th frame, stopping.");
+ SetPlanComplete();
+ return true;
+ }
+
+ StackID cur_frame_zero_id = cur_frame_sp->GetStackID();
if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id)
{
@@ -180,6 +189,24 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
{
if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol)
{
+ // next-instruction shouldn't step out of inlined functions. But we may have stepped into a
+ // real function that starts with an inlined function, and we do want to step out of that...
+
+ if (cur_frame_sp->IsInlined())
+ {
+ StackFrameSP parent_frame_sp = m_thread.GetFrameWithStackID(m_stack_id);
+
+ if(parent_frame_sp && parent_frame_sp->GetConcreteFrameIndex() == cur_frame_sp->GetConcreteFrameIndex())
+ {
+ SetPlanComplete();
+ if (log)
+ {
+ log->Printf("Frame we stepped into is inlined into the frame we were stepping from, stopping.");
+ }
+ return true;
+ }
+ }
+
if (log)
{
StreamString s;
diff --git a/source/Target/ThreadPlanStepOut.cpp b/source/Target/ThreadPlanStepOut.cpp
index b62f557319a8..0ded99b3091d 100644
--- a/source/Target/ThreadPlanStepOut.cpp
+++ b/source/Target/ThreadPlanStepOut.cpp
@@ -54,7 +54,6 @@ ThreadPlanStepOut::ThreadPlanStepOut
m_return_addr (LLDB_INVALID_ADDRESS),
m_stop_others (stop_others),
m_immediate_step_from_function(NULL)
-
{
SetFlagsToDefault();
SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
@@ -90,6 +89,7 @@ ThreadPlanStepOut::ThreadPlanStepOut
frame_idx - 1,
eLazyBoolNo));
static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())->SetShouldStopHereCallbacks(nullptr, nullptr);
+ m_step_out_to_inline_plan_sp->SetPrivate(true);
}
else
{
@@ -177,10 +177,34 @@ ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
else if (m_step_through_inline_plan_sp)
s->Printf ("Stepping out by stepping through inlined function.");
else
- s->Printf ("Stepping out from address 0x%" PRIx64 " to return address 0x%" PRIx64 " using breakpoint site %d",
- (uint64_t)m_step_from_insn,
- (uint64_t)m_return_addr,
- m_return_bp_id);
+ {
+ s->Printf ("Stepping out from ");
+ Address tmp_address;
+ if (tmp_address.SetLoadAddress (m_step_from_insn, &GetTarget()))
+ {
+ tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress);
+ }
+ else
+ {
+ s->Printf ("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn);
+ }
+
+ // FIXME: find some useful way to present the m_return_id, since there may be multiple copies of the
+ // same function on the stack.
+
+ s->Printf ("returning to frame at ");
+ if (tmp_address.SetLoadAddress (m_return_addr, &GetTarget()))
+ {
+ tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress);
+ }
+ else
+ {
+ s->Printf ("address 0x%" PRIx64 "", (uint64_t)m_return_addr);
+ }
+
+ if (level == eDescriptionLevelVerbose)
+ s->Printf(" using breakpoint site %d", m_return_bp_id);
+ }
}
}
@@ -474,11 +498,16 @@ ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)
inlined_sc.target_sp = GetTarget().shared_from_this();
RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
const LazyBool avoid_no_debug = eLazyBoolNo;
- ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread,
- inline_range,
- inlined_sc,
- run_mode,
- avoid_no_debug);
+
+ m_step_through_inline_plan_sp.reset (new ThreadPlanStepOverRange(m_thread,
+ inline_range,
+ inlined_sc,
+ run_mode,
+ avoid_no_debug));
+ ThreadPlanStepOverRange *step_through_inline_plan_ptr
+ = static_cast<ThreadPlanStepOverRange *>(m_step_through_inline_plan_sp.get());
+ m_step_through_inline_plan_sp->SetPrivate(true);
+
step_through_inline_plan_ptr->SetOkayToDiscard(true);
StreamString errors;
if (!step_through_inline_plan_ptr->ValidatePlan(&errors))
@@ -493,7 +522,7 @@ ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)
if (inlined_block->GetRangeAtIndex (i, inline_range))
step_through_inline_plan_ptr->AddRange (inline_range);
}
- m_step_through_inline_plan_sp.reset (step_through_inline_plan_ptr);
+
if (queue_now)
m_thread.QueueThreadPlan (m_step_through_inline_plan_sp, false);
return true;
diff --git a/source/Target/ThreadPlanStepOverBreakpoint.cpp b/source/Target/ThreadPlanStepOverBreakpoint.cpp
index dc011e545402..6f285e25fd0b 100644
--- a/source/Target/ThreadPlanStepOverBreakpoint.cpp
+++ b/source/Target/ThreadPlanStepOverBreakpoint.cpp
@@ -64,11 +64,33 @@ ThreadPlanStepOverBreakpoint::DoPlanExplainsStop (Event *event_ptr)
StopInfoSP stop_info_sp = GetPrivateStopInfo ();
if (stop_info_sp)
{
+ // It's a little surprising that we stop here for a breakpoint hit. However, when you single step ONTO a breakpoint
+ // we still want to call that a breakpoint hit, and trigger the actions, etc. Otherwise you would see the
+ // PC at the breakpoint without having triggered the actions, then you'd continue, the PC wouldn't change,
+ // and you'd see the breakpoint hit, which would be odd.
+ // So the lower levels fake "step onto breakpoint address" and return that as a breakpoint. So our trace
+ // step COULD appear as a breakpoint hit if the next instruction also contained a breakpoint.
StopReason reason = stop_info_sp->GetStopReason();
- if (reason == eStopReasonTrace || reason == eStopReasonNone)
+
+ switch (reason)
+ {
+ case eStopReasonTrace:
+ case eStopReasonNone:
return true;
- else
+ case eStopReasonBreakpoint:
+ // It's a little surprising that we stop here for a breakpoint hit. However, when you single step ONTO a
+ // breakpoint we still want to call that a breakpoint hit, and trigger the actions, etc. Otherwise you
+ // would see the PC at the breakpoint without having triggered the actions, then you'd continue, the PC
+ // wouldn't change, and you'd see the breakpoint hit, which would be odd.
+ // So the lower levels fake "step onto breakpoint address" and return that as a breakpoint hit. So our trace
+ // step COULD appear as a breakpoint hit if the next instruction also contained a breakpoint. We don't want
+ // to handle that, since we really don't know what to do with breakpoint hits. But make sure we don't set
+ // ourselves to auto-continue or we'll wrench control away from the plans that can deal with this.
+ SetAutoContinue(false);
+ return false;
+ default:
return false;
+ }
}
return false;
}
@@ -76,7 +98,7 @@ ThreadPlanStepOverBreakpoint::DoPlanExplainsStop (Event *event_ptr)
bool
ThreadPlanStepOverBreakpoint::ShouldStop (Event *event_ptr)
{
- return false;
+ return !ShouldAutoContinue(event_ptr);
}
bool
@@ -163,3 +185,10 @@ ThreadPlanStepOverBreakpoint::ShouldAutoContinue (Event *event_ptr)
{
return m_auto_continue;
}
+
+bool
+ThreadPlanStepOverBreakpoint::IsPlanStale()
+{
+ return m_thread.GetRegisterContext()->GetPC() != m_breakpoint_addr;
+}
+
diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp
index a4f3743346e2..a6d65e4d8116 100644
--- a/source/Target/ThreadPlanStepOverRange.cpp
+++ b/source/Target/ThreadPlanStepOverRange.cpp
@@ -62,12 +62,26 @@ void
ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
+ {
s->Printf("step over");
- else
+ return;
+ }
+ s->Printf ("Stepping over");
+ bool printed_line_info = false;
+ if (m_addr_context.line_entry.IsValid())
+ {
+ s->Printf (" line ");
+ m_addr_context.line_entry.DumpStopContext (s, false);
+ printed_line_info = true;
+ }
+
+ if (!printed_line_info || level == eDescriptionLevelVerbose)
{
- s->Printf ("stepping through range (stepping over functions): ");
- DumpRanges(s);
+ s->Printf (" using ranges: ");
+ DumpRanges(s);
}
+
+ s->PutChar('.');
}
void
@@ -317,11 +331,15 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
{
new_plan_sp = CheckShouldStopHereAndQueueStepOut (frame_order);
}
-
+
if (!new_plan_sp)
m_no_more_plans = true;
else
+ {
+ // Any new plan will be an implementation plan, so mark it private:
+ new_plan_sp->SetPrivate(true);
m_no_more_plans = false;
+ }
if (!new_plan_sp)
{
diff --git a/source/Target/ThreadPlanStepRange.cpp b/source/Target/ThreadPlanStepRange.cpp
index 82ca59fbca39..adc515cebc08 100644
--- a/source/Target/ThreadPlanStepRange.cpp
+++ b/source/Target/ThreadPlanStepRange.cpp
@@ -44,7 +44,8 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others) :
+ lldb::RunMode stop_others,
+ bool given_ranges_only) :
ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
m_addr_context (addr_context),
m_address_ranges (),
@@ -53,7 +54,8 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
m_parent_stack_id(),
m_no_more_plans (false),
m_first_run_event (true),
- m_use_fast_step(false)
+ m_use_fast_step(false),
+ m_given_ranges_only (given_ranges_only)
{
m_use_fast_step = GetTarget().GetUseFastStepping();
AddRange(range);
@@ -149,7 +151,7 @@ ThreadPlanStepRange::InRange ()
break;
}
- if (!ret_value)
+ if (!ret_value && !m_given_ranges_only)
{
// See if we've just stepped to another part of the same line number...
StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
diff --git a/source/Target/ThreadPlanStepThrough.cpp b/source/Target/ThreadPlanStepThrough.cpp
index 18da6cdbd59c..5b50a41a6398 100644
--- a/source/Target/ThreadPlanStepThrough.cpp
+++ b/source/Target/ThreadPlanStepThrough.cpp
@@ -87,7 +87,10 @@ ThreadPlanStepThrough::DidPush ()
void
ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC()
{
- m_sub_plan_sp = m_thread.GetProcess()->GetDynamicLoader()->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
+ DynamicLoader *loader = m_thread.GetProcess()->GetDynamicLoader();
+ if (loader)
+ m_sub_plan_sp = loader->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
+
// If that didn't come up with anything, try the ObjC runtime plugin:
if (!m_sub_plan_sp.get())
{
diff --git a/source/Target/ThreadPlanTracer.cpp b/source/Target/ThreadPlanTracer.cpp
index 5188df6d9193..d2b039d69f67 100644
--- a/source/Target/ThreadPlanTracer.cpp
+++ b/source/Target/ThreadPlanTracer.cpp
@@ -212,11 +212,15 @@ ThreadPlanAssemblyTracer::Log ()
const bool show_bytes = true;
const bool show_address = true;
Instruction *instruction = instruction_list.GetInstructionAtIndex(0).get();
+ const char *disassemble_format = "${addr-file-or-load}: ";
instruction->Dump (stream,
max_opcode_byte_size,
show_address,
show_bytes,
- NULL);
+ NULL,
+ NULL,
+ NULL,
+ disassemble_format);
}
}
}
diff --git a/source/Utility/PseudoTerminal.cpp b/source/Utility/PseudoTerminal.cpp
index c906ea273005..e90955d37d4c 100644
--- a/source/Utility/PseudoTerminal.cpp
+++ b/source/Utility/PseudoTerminal.cpp
@@ -31,6 +31,8 @@ char *ptsname(int fd) { return 0; }
pid_t fork(void) { return 0; }
pid_t setsid(void) { return 0; }
+#elif defined(__ANDROID_NDK__)
+#include "lldb/Host/android/Android.h"
#endif
using namespace lldb_utility;
@@ -66,7 +68,11 @@ PseudoTerminal::CloseMasterFileDescriptor ()
{
if (m_master_fd >= 0)
{
+ // Don't call 'close' on m_master_fd for Windows as a dummy implementation of
+ // posix_openpt above always gives it a 0 value.
+#ifndef _WIN32
::close (m_master_fd);
+#endif
m_master_fd = invalid_fd;
}
}
diff --git a/source/Utility/RegisterNumber.cpp b/source/Utility/RegisterNumber.cpp
new file mode 100644
index 000000000000..8116cda10fe5
--- /dev/null
+++ b/source/Utility/RegisterNumber.cpp
@@ -0,0 +1,157 @@
+//===--------------------- RegisterNumber.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/RegisterNumber.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+
+using namespace lldb_private;
+
+
+RegisterNumber::RegisterNumber (lldb_private::Thread &thread, lldb::RegisterKind kind, uint32_t num) :
+ m_reg_ctx_sp (thread.GetRegisterContext()),
+ m_regnum (num),
+ m_kind (kind),
+ m_kind_regnum_map (),
+ m_name ("")
+{
+ if (m_reg_ctx_sp.get())
+ {
+ const lldb_private::RegisterInfo *reginfo = m_reg_ctx_sp->GetRegisterInfoAtIndex (GetAsKind (lldb::eRegisterKindLLDB));
+ if (reginfo && reginfo->name)
+ {
+ m_name = reginfo->name;
+ }
+ }
+}
+
+RegisterNumber::RegisterNumber () :
+ m_reg_ctx_sp(),
+ m_regnum (LLDB_INVALID_REGNUM),
+ m_kind (lldb::kNumRegisterKinds),
+ m_kind_regnum_map (),
+ m_name (nullptr)
+{
+}
+
+void
+RegisterNumber::init (lldb_private::Thread &thread, lldb::RegisterKind kind, uint32_t num)
+{
+ m_reg_ctx_sp = thread.GetRegisterContext();
+ m_regnum = num;
+ m_kind = kind;
+ if (m_reg_ctx_sp.get())
+ {
+ const lldb_private::RegisterInfo *reginfo = m_reg_ctx_sp->GetRegisterInfoAtIndex (GetAsKind (lldb::eRegisterKindLLDB));
+ if (reginfo && reginfo->name)
+ {
+ m_name = reginfo->name;
+ }
+ }
+}
+
+const RegisterNumber &
+RegisterNumber::operator = (const RegisterNumber &rhs)
+{
+ m_reg_ctx_sp = rhs.m_reg_ctx_sp;
+ m_regnum = rhs.m_regnum;
+ m_kind = rhs.m_kind;
+ for (auto it : rhs.m_kind_regnum_map)
+ m_kind_regnum_map[it.first] = it.second;
+ m_name = rhs.m_name;
+ return *this;
+}
+
+bool
+RegisterNumber::operator == (RegisterNumber &rhs)
+{
+ if (IsValid() != rhs.IsValid())
+ return false;
+
+ if (m_kind == rhs.m_kind)
+ {
+ if (m_regnum == rhs.m_regnum)
+ return true;
+ else
+ return false;
+ }
+
+ uint32_t rhs_regnum = rhs.GetAsKind (m_kind);
+ if (rhs_regnum != LLDB_INVALID_REGNUM)
+ {
+ if (m_regnum == rhs_regnum)
+ return true;
+ else
+ return false;
+ }
+ uint32_t lhs_regnum = GetAsKind (rhs.m_kind);
+ {
+ if (lhs_regnum == rhs.m_regnum)
+ return true;
+ else
+ return false;
+ }
+ return false;
+}
+
+bool
+RegisterNumber::operator != (RegisterNumber &rhs)
+{
+ return !(*this == rhs);
+}
+
+bool
+RegisterNumber::IsValid () const
+{
+ return m_reg_ctx_sp.get()
+ && m_kind != lldb::kNumRegisterKinds
+ && m_regnum != LLDB_INVALID_REGNUM;
+}
+
+uint32_t
+RegisterNumber::GetAsKind (lldb::RegisterKind kind)
+{
+ if (m_regnum == LLDB_INVALID_REGNUM)
+ return LLDB_INVALID_REGNUM;
+
+ if (kind == m_kind)
+ return m_regnum;
+
+ Collection::iterator iter = m_kind_regnum_map.find (kind);
+ if (iter != m_kind_regnum_map.end())
+ {
+ return iter->second;
+ }
+ uint32_t output_regnum = LLDB_INVALID_REGNUM;
+ if (m_reg_ctx_sp
+ && m_reg_ctx_sp->ConvertBetweenRegisterKinds (m_kind, m_regnum, kind, output_regnum)
+ && output_regnum != LLDB_INVALID_REGNUM)
+ {
+ m_kind_regnum_map[kind] = output_regnum;
+ }
+ return output_regnum;
+}
+
+uint32_t
+RegisterNumber::GetRegisterNumber () const
+{
+ return m_regnum;
+}
+
+lldb::RegisterKind
+RegisterNumber::GetRegisterKind () const
+{
+ return m_kind;
+}
+
+const char *
+RegisterNumber::GetName ()
+{
+ return m_name;
+}
diff --git a/source/Utility/StringExtractor.cpp b/source/Utility/StringExtractor.cpp
index 8747853213cb..a2cbe6cd4869 100644
--- a/source/Utility/StringExtractor.cpp
+++ b/source/Utility/StringExtractor.cpp
@@ -16,43 +16,6 @@
// Other libraries and framework includes
// Project includes
-static const uint8_t
-g_hex_ascii_to_hex_integer[256] = {
-
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
- 0x8, 0x9, 255, 255, 255, 255, 255, 255,
- 255, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
-};
-
static inline int
xdigit_to_sint (char ch)
{
@@ -60,7 +23,9 @@ xdigit_to_sint (char ch)
return 10 + ch - 'a';
if (ch >= 'A' && ch <= 'F')
return 10 + ch - 'A';
- return ch - '0';
+ if (ch >= '0' && ch <= '9')
+ return ch - '0';
+ return -1;
}
//----------------------------------------------------------------------
@@ -129,25 +94,45 @@ StringExtractor::GetChar (char fail_value)
}
//----------------------------------------------------------------------
+// If a pair of valid hex digits exist at the head of the
+// StringExtractor they are decoded into an unsigned byte and returned
+// by this function
+//
+// If there is not a pair of valid hex digits at the head of the
+// StringExtractor, it is left unchanged and -1 is returned
+//----------------------------------------------------------------------
+int
+StringExtractor::DecodeHexU8()
+{
+ if (GetBytesLeft() < 2)
+ {
+ return -1;
+ }
+ const int hi_nibble = xdigit_to_sint(m_packet[m_index]);
+ const int lo_nibble = xdigit_to_sint(m_packet[m_index+1]);
+ if (hi_nibble == -1 || lo_nibble == -1)
+ {
+ return -1;
+ }
+ m_index += 2;
+ return (uint8_t)((hi_nibble << 4) + lo_nibble);
+}
+
+//----------------------------------------------------------------------
// Extract an unsigned character from two hex ASCII chars in the packet
// string
//----------------------------------------------------------------------
uint8_t
StringExtractor::GetHexU8 (uint8_t fail_value, bool set_eof_on_fail)
{
- if (GetBytesLeft() >= 2)
+ int byte = DecodeHexU8();
+ if (byte == -1)
{
- const uint8_t hi_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[m_index])];
- const uint8_t lo_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[m_index+1])];
- if (hi_nibble < 16 && lo_nibble < 16)
- {
- m_index += 2;
- return (hi_nibble << 4) + lo_nibble;
- }
+ if (set_eof_on_fail || m_index >= m_packet.size())
+ m_index = UINT64_MAX;
+ return fail_value;
}
- if (set_eof_on_fail || m_index >= m_packet.size())
- m_index = UINT64_MAX;
- return fail_value;
+ return (uint8_t)byte;
}
uint32_t
@@ -372,6 +357,28 @@ StringExtractor::GetHexBytes (void *dst_void, size_t dst_len, uint8_t fail_fill_
return bytes_extracted;
}
+//----------------------------------------------------------------------
+// Decodes all valid hex encoded bytes at the head of the
+// StringExtractor, limited by dst_len.
+//
+// Returns the number of bytes successfully decoded
+//----------------------------------------------------------------------
+size_t
+StringExtractor::GetHexBytesAvail (void *dst_void, size_t dst_len)
+{
+ uint8_t *dst = (uint8_t*)dst_void;
+ size_t bytes_extracted = 0;
+ while (bytes_extracted < dst_len)
+ {
+ int decode = DecodeHexU8();
+ if (decode == -1)
+ {
+ break;
+ }
+ dst[bytes_extracted++] = (uint8_t)decode;
+ }
+ return bytes_extracted;
+}
// Consume ASCII hex nibble character pairs until we have decoded byte_size
// bytes of data.
diff --git a/source/Utility/StringExtractor.h b/source/Utility/StringExtractor.h
index 697499309ced..49dfe99bd358 100644
--- a/source/Utility/StringExtractor.h
+++ b/source/Utility/StringExtractor.h
@@ -92,9 +92,13 @@ public:
return m_packet.size() - m_index;
return 0;
}
+
char
GetChar (char fail_value = '\0');
+ int
+ DecodeHexU8();
+
uint8_t
GetHexU8 (uint8_t fail_value = 0, bool set_eof_on_fail = true);
@@ -122,6 +126,9 @@ public:
size_t
GetHexBytes (void *dst, size_t dst_len, uint8_t fail_fill_value);
+ size_t
+ GetHexBytesAvail (void *dst, size_t dst_len);
+
uint64_t
GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value);
diff --git a/source/Utility/StringExtractorGDBRemote.cpp b/source/Utility/StringExtractorGDBRemote.cpp
index 17717dbe6e20..161ac6a026f2 100644
--- a/source/Utility/StringExtractorGDBRemote.cpp
+++ b/source/Utility/StringExtractorGDBRemote.cpp
@@ -346,14 +346,15 @@ StringExtractorGDBRemote::GetError ()
size_t
StringExtractorGDBRemote::GetEscapedBinaryData (std::string &str)
{
+ // Just get the data bytes in the string as GDBRemoteCommunication::CheckForPacket()
+ // already removes any 0x7d escaped characters. If any 0x7d characters are left in
+ // the packet, then they are supposed to be there...
str.clear();
- char ch;
- while (GetBytesLeft())
+ const size_t bytes_left = GetBytesLeft();
+ if (bytes_left > 0)
{
- ch = GetChar();
- if (ch == 0x7d)
- ch = (GetChar() ^ 0x20);
- str.append(1,ch);
+ str.assign(m_packet, m_index, bytes_left);
+ m_index += bytes_left;
}
return str.size();
}
diff --git a/source/Utility/StringLexer.cpp b/source/Utility/StringLexer.cpp
index bde2fc6a4202..2f62d2cedb40 100644
--- a/source/Utility/StringLexer.cpp
+++ b/source/Utility/StringLexer.cpp
@@ -10,28 +10,24 @@
#include "lldb/Utility/StringLexer.h"
#include <algorithm>
+#include <assert.h>
using namespace lldb_utility;
StringLexer::StringLexer (std::string s) :
-m_data(s),
-m_position(0),
-m_putback_data()
+ m_data(s),
+ m_position(0)
{ }
StringLexer::StringLexer (const StringLexer& rhs) :
-m_data(rhs.m_data),
-m_position(rhs.m_position),
-m_putback_data(rhs.m_putback_data)
+ m_data(rhs.m_data),
+ m_position(rhs.m_position)
{ }
StringLexer::Character
StringLexer::Peek ()
{
- if (m_putback_data.empty())
- return m_data[m_position];
- else
- return m_putback_data.front();
+ return m_data[m_position];
}
bool
@@ -46,6 +42,42 @@ StringLexer::NextIf (Character c)
return false;
}
+std::pair<bool, StringLexer::Character>
+StringLexer::NextIf (std::initializer_list<Character> cs)
+{
+ auto val = Peek();
+ for (auto c : cs)
+ {
+ if (val == c)
+ {
+ Next();
+ return {true,c};
+ }
+ }
+ return {false,0};
+}
+
+bool
+StringLexer::AdvanceIf (const std::string& token)
+{
+ auto pos = m_position;
+ bool matches = true;
+ for (auto c : token)
+ {
+ if (!NextIf(c))
+ {
+ matches = false;
+ break;
+ }
+ }
+ if (!matches)
+ {
+ m_position = pos;
+ return false;
+ }
+ return true;
+}
+
StringLexer::Character
StringLexer::Next ()
{
@@ -57,35 +89,32 @@ StringLexer::Next ()
bool
StringLexer::HasAtLeast (Size s)
{
- auto in_m_data = m_data.size()-m_position;
- auto in_putback = m_putback_data.size();
- return (in_m_data + in_putback >= s);
+ return (m_data.size() - m_position) >= s;
}
-
void
-StringLexer::PutBack (Character c)
+StringLexer::PutBack (Size s)
{
- m_putback_data.push_back(c);
+ assert (m_position >= s);
+ m_position -= s;
}
bool
StringLexer::HasAny (Character c)
{
- const auto begin(m_putback_data.begin());
- const auto end(m_putback_data.end());
- if (std::find(begin, end, c) != end)
- return true;
return m_data.find(c, m_position) != std::string::npos;
}
+std::string
+StringLexer::GetUnlexed ()
+{
+ return std::string(m_data, m_position);
+}
+
void
StringLexer::Consume()
{
- if (m_putback_data.empty())
- m_position++;
- else
- m_putback_data.pop_front();
+ m_position++;
}
StringLexer&
@@ -95,7 +124,6 @@ StringLexer::operator = (const StringLexer& rhs)
{
m_data = rhs.m_data;
m_position = rhs.m_position;
- m_putback_data = rhs.m_putback_data;
}
return *this;
}
diff --git a/source/Utility/UriParser.cpp b/source/Utility/UriParser.cpp
new file mode 100644
index 000000000000..bf1e601485b4
--- /dev/null
+++ b/source/Utility/UriParser.cpp
@@ -0,0 +1,58 @@
+//===-- UriParser.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Utility/UriParser.h"
+
+// C Includes
+#include <stdlib.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+//----------------------------------------------------------------------
+// UriParser::Parse
+//----------------------------------------------------------------------
+bool
+UriParser::Parse(const char* uri,
+ std::string& scheme,
+ std::string& hostname,
+ int& port,
+ std::string& path
+ )
+{
+ char scheme_buf[100] = {0};
+ char hostname_buf[256] = {0};
+ char port_buf[11] = {0}; // 10==strlen(2^32)
+ char path_buf[2049] = {'/', 0};
+
+ bool ok = false;
+ if (4==sscanf(uri, "%99[^:/]://%255[^/:]:%[^/]/%2047s", scheme_buf, hostname_buf, port_buf, path_buf+1)) { ok = true; }
+ else if (3==sscanf(uri, "%99[^:/]://%255[^/:]:%[^/]", scheme_buf, hostname_buf, port_buf)) { ok = true; }
+ else if (3==sscanf(uri, "%99[^:/]://%255[^/]/%2047s", scheme_buf, hostname_buf, path_buf+1)) { ok = true; }
+ else if (2==sscanf(uri, "%99[^:/]://%255[^/]", scheme_buf, hostname_buf)) { ok = true; }
+
+ char* end = port_buf;
+ int port_tmp = strtoul(port_buf, &end, 10);
+ if (*end != 0)
+ {
+ // there are invalid characters in port_buf
+ return false;
+ }
+
+ if (ok)
+ {
+ scheme.assign(scheme_buf);
+ hostname.assign(hostname_buf);
+ port = port_tmp;
+ path.assign(path_buf);
+ }
+ return ok;
+}
+
diff --git a/source/Utility/UriParser.h b/source/Utility/UriParser.h
new file mode 100644
index 000000000000..c46628d3bd68
--- /dev/null
+++ b/source/Utility/UriParser.h
@@ -0,0 +1,31 @@
+//===-- UriParser.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_UriParser_h_
+#define utility_UriParser_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+
+class UriParser
+{
+public:
+ static bool Parse(const char* uri,
+ std::string& scheme,
+ std::string& hostname,
+ int& port,
+ std::string& path
+ );
+};
+
+#endif // utility_UriParser_h_
diff --git a/source/lldb-log.cpp b/source/lldb-log.cpp
index 4311c1ad084f..463de137f623 100644
--- a/source/lldb-log.cpp
+++ b/source/lldb-log.cpp
@@ -11,6 +11,7 @@
// C Includes
// C++ Includes
+#include <atomic>
// Other libraries and framework includes
// Project includes
#include "lldb/Interpreter/Args.h"
@@ -27,7 +28,7 @@ using namespace lldb_private;
// that will construct the static g_lob_sp the first time this function is
// called.
-static bool g_log_enabled = false;
+static std::atomic<bool> g_log_enabled {false};
static Log * g_log = NULL;
static Log *
GetLog ()
diff --git a/source/lldb.cpp b/source/lldb.cpp
index cd620b7945b9..2ac8296b4d04 100644
--- a/source/lldb.cpp
+++ b/source/lldb.cpp
@@ -31,6 +31,8 @@
#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"
@@ -81,6 +83,8 @@
#endif
#if defined (_WIN32)
+#include "lldb/Host/windows/windows.h"
+#include "Plugins/Process/Windows/DynamicLoaderWindows.h"
#include "Plugins/Process/Windows/ProcessWindows.h"
#endif
@@ -92,6 +96,8 @@
#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;
@@ -113,6 +119,25 @@ lldb_private::Initialize ()
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 ();
@@ -130,6 +155,8 @@ lldb_private::Initialize ()
ABIMacOSX_arm::Initialize();
ABIMacOSX_arm64::Initialize();
ABISysV_x86_64::Initialize();
+ ABISysV_ppc::Initialize();
+ ABISysV_ppc64::Initialize();
DisassemblerLLVMC::Initialize();
ObjectContainerBSDArchive::Initialize();
ObjectFileELF::Initialize();
@@ -154,6 +181,8 @@ lldb_private::Initialize ()
#endif
JITLoaderGDB::Initialize();
ProcessElfCore::Initialize();
+ MemoryHistoryASan::Initialize();
+ AddressSanitizerRuntime::Initialize();
#if defined (__APPLE__)
//----------------------------------------------------------------------
@@ -181,6 +210,7 @@ lldb_private::Initialize ()
ProcessLinux::Initialize();
#endif
#if defined(_WIN32)
+ DynamicLoaderWindows::Initialize();
ProcessWindows::Initialize();
#endif
#if defined (__FreeBSD__)
@@ -221,6 +251,8 @@ lldb_private::Terminate ()
ABIMacOSX_arm::Terminate();
ABIMacOSX_arm64::Terminate();
ABISysV_x86_64::Terminate();
+ ABISysV_ppc::Terminate();
+ ABISysV_ppc64::Terminate();
DisassemblerLLVMC::Terminate();
ObjectContainerBSDArchive::Terminate();
ObjectFileELF::Terminate();
@@ -244,6 +276,8 @@ lldb_private::Terminate ()
#endif
JITLoaderGDB::Terminate();
ProcessElfCore::Terminate();
+ MemoryHistoryASan::Terminate();
+ AddressSanitizerRuntime::Terminate();
#if defined (__APPLE__)
DynamicLoaderMacOSXDYLD::Terminate();
@@ -264,6 +298,10 @@ lldb_private::Terminate ()
Debugger::SettingsTerminate ();
+#if defined (_WIN32)
+ DynamicLoaderWindows::Terminate();
+#endif
+
#if defined (__linux__)
ProcessLinux::Terminate();
#endif
@@ -425,6 +463,7 @@ lldb_private::GetSectionTypeAsCString (SectionType sect_type)
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";